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();
}
}
工作bean:
@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);
}
}
}
还有一些可能的变化,例如您可以将繁忙检查委托给拦截器,或者将仅包含布尔值的单例注入计时器 bean,并在那里检查该布尔值等.
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屋!