EJB @Schedule等到方法完成 [英] EJB @Schedule wait until method completed
问题描述
我想编写一个后台作业(EJB 3.1),它每分钟执行一次。为此,我使用以下注释:
I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:
@Schedule(minute = "*/1", hour = "*")
工作正常。
但是,有时这项工作可能需要一分多钟。在这种情况下,计时器仍然被触发,导致线程问题。
However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.
如果当前执行没有完成,是否可以终止调度程序?
Is it somehow possible, to terminate the scheduler if the current execution is not completed?
推荐答案
如果同时只有1个计时器可能处于活动状态,则有几种解决方案。
If only 1 timer may ever be active at the same time, there are a couple of solutions.
首先, @Timer
应该出现在 @Singleton
上。在Singleton方法中,默认情况下是写锁定的,因此在尝试调用计时器方法时,容器将自动被锁定,同时仍有活动。
First of all the @Timer
should probably be present on an @Singleton
. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.
以下基本上就足够了:
@Singleton
public class TimerBean {
@Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
atSchedule
默认是写锁定的,并且只能有一个活动的线程,包括容器发起的调用。
atSchedule
is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.
被锁定后,容器可能会重试计时器,所以为了防止这种情况,你要使用读锁定并委托给第二个bean(需要第二个bean,因为EJB 3.1不允许将读锁升级到写锁)。
Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).
计时器bean:
@Singleton
public class TimerBean {
@EJB
private WorkerBean workerBean;
@Lock(READ)
@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
try {
workerBean.doTimerWork();
} catch (Exception e) {
System.out.println("Timer still busy");
}
}
}
工人bean:
@Singleton
public class WorkerBean {
@AccessTimeout(0)
public void doTimerWork() throws InterruptedException {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
}
}
这可能仍会在日志中打印出嘈杂的异常,所以一个更冗长但更安静的解决方案是使用显式布尔值:
This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:
计时器bean:
@Singleton
public class TimerBean {
@EJB
private WorkerBean workerBean;
@Lock(READ)
@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
工人豆:
@Singleton
public class WorkerBean {
private AtomicBoolean busy = new AtomicBoolean(false);
@Lock(READ)
public void doTimerWork() throws InterruptedException {
if (!busy.compareAndSet(false, true)) {
return;
}
try {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
} finally {
busy.set(false);
}
}
}
有可能的更多变化,例如你可以将繁忙的检查委托给一个拦截器,或者将一个只包含boolean的单例注入到计时器bean中,然后在那里检查那个boolean等。
There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.
这篇关于EJB @Schedule等到方法完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!