我有一个执行器服务,它定期执行一堆任务。它们在启动时初始化并且经常运行,到目前为止一直很好。
我现在想添加一些功能,以根据事件快速启动这些任务的执行。
我找到了decorateTask方法,它允许我存储我安排的任务。但是,我不确定如何让它们运行?
我有想法在RunnableScheduledFuture中覆盖Delayed方法让它在预定义的事件上返回0,但是我也不确定这是否可行以及如果我这样做会执行者的行为如何?
另一个想法是收集所有任务,然后直接在事件上提交它们。也不确定这会如何表现。
我不能只调用它们,因为它们将在同一个线程中运行。
我希望这一切都有道理。如果有什么不清楚,请告诉我。
public class EventBasedExecutor extends ScheduledThreadPoolExecutor implements EventBasedExecutorService {
private static final Logger log = Logger.getLogger(EventBasedExecutor.class);
private List<RunnableScheduledFuture<?>> workers = new ArrayList<>();
public EventBasedExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, threadFactory);
}
@Override
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
workers.add(task);
return super.decorateTask(runnable, task);
}
@Override
public void executeEarly() {
// do something here to start the executors work
}
答案 0 :(得分:1)
最简洁易懂的方法是收集所有任务并直接在事件中运行。我只需要使用ExecutorService的invokeAll。以下代码示例可以提供帮助:
public void handleSomeEvent(Event event) {
List<Task> tasksToRunOnEvent = getTasksToRunOnEvent(event);
List<Future<TaskResult> futures = executorService.invokeAll(tasksToRunOnEvent);
handleTaskResults(futures);
}
答案 1 :(得分:0)
我接受了tvelykyy的建议并玩了一下,并想出了这个意思:
public class EventBasedExecutor extends ScheduledThreadPoolExecutor implements EventBasedExecutorService {
private List<RunnableScheduledFuture<?>> workers = new ArrayList<>();
private int index;
public EventBasedExecutor(int corePoolSize) {
super(corePoolSize, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("message-sender-%d").build());
}
@Override
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
if(!workers.contains(runnable)) {
workers.add(task);
}
return super.decorateTask(runnable, task);
}
@Override
public void executeEarly() {
if(index >= workers.size()) {
index = 0;
}
if(workers.size() == 0) {
return;
}
RunnableScheduledFuture<?> runnableScheduledFuture = workers.get(index);
index ++;
execute(runnableScheduledFuture);
}
}
几句话:
workers.contains(Runnable)是真的,如果你重新提交一个RunnableScheduledFuture。
你必须通过execute提交它才能让它在线程池中运行(而不是只在runnable上调用run来阻止当前线程)。
我建议使用runnables来实现一个安全防护装置,这样它们就不能同时执行两次(对我的用例很重要)。所以基本上:
if( isrunning() ) return;
在decorateTask中 - 你必须重新装饰runnable。这是因为如果必须的话,实现将采用包装的runnable并重新安排它。由于旧的runnable已经安排好,你不想重新安排它们。所以调用execute将遍历装饰并装饰预定的runnable(通常每秒或一些运行)作为不可重复的runnable。这意味着,您的计划任务可以在不重新计划的情况下运行一次,同时仍可作为执行程序中的定期运行。
我希望这一切都有道理:)
阿图尔