Phi*_* P. 36 java schedule java-ee job-scheduling ejb-3.1
我想编写一个后台作业(EJB 3.1),它每分钟执行一次.为此,我使用以下注释:
@Schedule(minute = "*/1", hour = "*")
Run Code Online (Sandbox Code Playgroud)
这工作正常.
但是,有时候这项工作可能需要一分多钟.在这种情况下,计时器仍然被触发,导致线程问题.
如果当前执行没有完成,是否可以终止调度程序?
Arj*_*jms 63
如果同时只有1个定时器可能处于活动状态,则有几种解决方案.
首先@Timer应该出现在一个@Singleton.在Singleton方法中,默认情况下是写锁定的,因此当尝试调用timer方法时,容器将自动被锁定,同时仍有活动.
以下基本上就足够了:
@Singleton
public class TimerBean {
@Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
Run Code Online (Sandbox Code Playgroud)
atSchedule 默认情况下是写锁定的,并且只能有一个活动的线程,包括容器启动的调用.
在被锁定时,容器可能会重试计时器,所以为了防止这种情况,你要使用读锁定并委托给第二个bean(需要第二个bean,因为EJB 3.1不允许将读锁升级到写锁).
计时器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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
工人豆:
@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");
}
}
Run Code Online (Sandbox Code Playgroud)
这可能仍会在日志中打印出一个嘈杂的异常,因此更详细但更安静的解决方案是使用显式布尔值:
计时器bean:
@Singleton
public class TimerBean {
@EJB
private WorkerBean workerBean;
@Lock(READ)
@Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
Run Code Online (Sandbox Code Playgroud)
工人豆:
@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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
还有一些可能的变化,例如你可以将繁忙的检查委托给一个拦截器,或者将一个只包含boolean的单例注入到计时器bean中,并在那里检查那个boolean等.
我遇到了同样的问题,但解决方法略有不同.
@Singleton
public class DoStuffTask {
@Resource
private TimerService timerSvc;
@Timeout
public void doStuff(Timer t) {
try {
doActualStuff(t);
} catch (Exception e) {
LOG.warn("Error running task", e);
}
scheduleStuff();
}
private void doActualStuff(Timer t) {
LOG.info("Doing Stuff " + t.getInfo());
}
@PostConstruct
public void initialise() {
scheduleStuff();
}
private void scheduleStuff() {
timerSvc.createSingleActionTimer(1000l, new TimerConfig());
}
public void stop() {
for(Timer timer : timerSvc.getTimers()) {
timer.cancel();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这通过设置将来执行的任务(在这种情况下,在一秒内)来工作.在任务结束时,它会再次安排任务.
编辑:更新以将"stuff"重构为另一种方法,以便我们可以防范异常,以便定期重新安排计时器
从Java EE 7开始,可以在WildFly中使用“可感知EE”的ManagedScheduledExecutorService:
例如@Singleton @Startup @LocalBean,在中注入默认配置中的“ managed-scheduled-executor-service” standalone.xml:
@Resource
private ManagedScheduledExecutorService scheduledExecutorService;
Run Code Online (Sandbox Code Playgroud)
安排一些任务@PostConstruct要执行,即每秒固定延迟地执行:
scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)
创建并执行一个周期性操作,该操作将在给定的初始延迟后首先启用,然后在一次执行的终止与下一次执行的开始之间具有给定的延迟。[...]
不要在ie中关闭调度程序@PreDestroy:
托管的计划执行程序服务实例由应用程序服务器管理,因此禁止Java EE应用程序调用任何与生命周期相关的方法。
| 归档时间: |
|
| 查看次数: |
42241 次 |
| 最近记录: |