Ответ 1
Если одновременно может быть активен только один таймер, есть несколько решений.
Прежде всего @Timer
должен присутствовать на @Singleton
. В методах Singleton по умолчанию блокируется запись, поэтому контейнер будет автоматически заблокирован при попытке вызвать метод таймера, пока в нем еще есть активность.
В основном достаточно:
@Singleton
public class TimerBean {
@Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
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");
}
}
}
Рабочий 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");
}
}
В журнале все равно будет отображаться шумное исключение, поэтому более подробное, но более тихое решение должно использовать явное логическое значение:
Таймер 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, и проверять, что boolean существует и т.д.