我偶尔发现自己需要在某个任意线程上运行代码或将 Runnable 传递给某个任意消费者,并且缺少 java.util.concurrent 的全部功能 - 例如,编写 Swing 和 JavaFX 应用程序,使用 SwingUtilities.invokeLater() 或 Platform.runLater() 将后台线程的 UI 更新发布到主 UI 线程。
将这样的 API 包装在执行器中非常简单:
class AppThreadExecutor implements Executor {
@Override
public void execute(Runnable command) {
if (Platform.isFxApplicationThread()) {
command.run();
} else {
Platform.runLater(command);
}
}
}
然而,这并没有真正让你得到太多;特别是,它不会让你Futures
,或者与有用的API进行任何交互,如Guava或Vavr中的API。
AbstractExecutorService 提供了将单个抽象方法执行器引导为完整 ExecutorService 所需的一些但不是全部方法。具体来说,它缺少shutdown()
、shutdownNow()
、isShutdown()
、isTerminated()
和awaitTermination()
。
我可以编写自己的实现(并且有),但我更喜欢现有的、经过良好测试的库类(甚至是具有不同性能特征或关闭保证的库类)。有这样的事情存在吗?
注意:这不是一个关于Swing或JavaFX的问题;这些只是可能需要从任意线程或类似Executor的任务运行器引导到完整ExecutorService的情况的示例。如果您对这些框架的错误方法有具体建议,我很感激,但请将其作为评论而不是答案。
如果你的目标是JavaFX,你可以尝试JRebirth应用程序框架,它提供了一个关于线程和内存问题的真正抽象。
无需操作未来,每个异步任务都使用内部事件总线(发送和处理内部消息)处理。 在幕后,它使用 2 个线程池来执行可运行,但也允许将任务运行到图形线程或内部消息线程中。
这种方法更容易学习的是阅读源代码:
- https://github.com/JRebirth/ComparisonTool
- https://github.com/JRebirth/MasteringTables
一些文档链接:
- http://jrebirth.org/doc/Overview.html
- http://jrebirth.org/doc/Thread.html
- http://jrebirth.org/doc/Facades.html