将任务移动到单独的线程,避免任务运行时重复和正确使用执行程序 + 未来



我们在遗留代码和当前代码之间有一个粘合组件。从本质上讲,整个遗留应用程序都是单线程的,并且存在可怕的问题,单个指令的ui刷新可能会发生5到8次。

我想在第一个更新请求发生+2秒后发布一条异步消息。

我们不要纠结于为什么,这不是我真正想做的,但我必须了解如何至少做到这一点,这样我才能实现真正的解决方案。

Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(2);
messageBus.publishAsynch(new LegacyUiUpdateEvent());
} catch (InterruptedException e) {
// TODO Log something
Thread.currentThread().interrupt();
}
};
@Override
public void update(Observable arg0, Object arg1) {
ExecutorService executor = Executors.newSingleThreadExecutor();
if (futureTask == null || futureTask.isDone()) {
futureTask = executor.submit(task);
try {
executor.awaitTermination(10, TimeUnit.SECONDS);
executor.shutdownNow();
} catch (InterruptedException e) {
// TODO Log something
Thread.currentThread().interrupt();
}
}
}

理论是:如果未来的任务不存在,我们创建它,一旦它存在,如果它没有完成(因为这是错误的遗留更新4/x,其中x∈[5,12],睡眠仍然有效),那么我们完全跳过,不创建新的执行者。

问题是,据我所知,executor.submit(task)实际上并没有发生在新胎面上。就像我说的那样,遗留应用程序是单线程的,在我将睡眠时间增加到15秒后,很明显,它正在将整个当前线程发送到睡眠状态。

我该如何将我的taks放在一个全新的线程上(使用concurrency库),并避免多次执行任务,即使更新方法被调用了太多次(这100%超出了我的控制范围)。我认为future.isDone()是可行的,但不是100%

如果您使用的是Java 8或更高版本,那么做会更好

CompletableFuture.runAsync(task);

因为这将在由JVM管理的Fork连接线程池上执行,您不会因为创建或关闭它而担心自己。当然,这将异步运行,这符合您的要求。

executor.submit()确实在新线程中启动任务,但紧接着executor.awaitTermination(10, TimeUnit.SECONDS);当前线程中等待任务完成。不需要在当前线程中等待,但确实需要有一种方法来确定任务是否已经在运行。

混乱的部分是每次都创建ExecutorService——没有必要每次都重新创建它。它可以是类的实例变量,并可以重复使用。理想情况下,它将通过构造函数注入,这样创建它的类就可以在真正需要的时候关闭它。

private final ExecutorService executor = Executors.newSingleThreadExecutor();  // or injected through constructor
private Future<?> futureTask;
@Override
public void update(Observable arg0, Object arg1) {
if (futureTask == null || futureTask.isDone()) {
futureTask = executor.submit(task);
}
}

相关内容

  • 没有找到相关文章

最新更新