我尝试使用Java的FutureTask,Future,Runnable,Callable和ExecutorService类型.
构建这些构建块的最佳实践是什么?
鉴于我有多个FutureTasks并且我想按顺序执行它们.
当然,我可以创建另一个FutureTask,它按顺序提交/等待每个子任务的结果,但我想避免阻塞调用.
另一种选择是让这些子任务在完成时调用回调,并在回调中安排下一个任务.但是走这条路,如何创建一个合适的外部FutureTask对象,它也处理子任务中的异常而不会产生那么多的样板?
我在这里想念一下吗?
要在ExecutorService上执行的Runnables不应该阻止.这是因为每个阻塞都会关闭一个工作线程,如果ExecutorService的工作线程数量有限,则存在陷入死锁(线程饥饿)的风险,如果ExecutorService具有无限数量的工作线程,则存在风险内存耗尽.阻塞任务中的操作只会破坏ExecutorService的所有优点,因此仅在常用线程上使用阻塞操作.
FutureTask.get()是阻塞操作,因此可以在普通线程上使用,而不是在ExecutorService任务中使用.也就是说,它不能用作构建块,而只能将执行结果传递给主线程.
从任务构建执行的正确方法是在下一个任务的所有输入数据都准备就绪时启动下一个任务,这样任务就不必阻止等待输入数据.因此,您需要一种存储中间结果的门,并在所有参数到达时启动新任务.因此,任务不会明确地开始其他任务.因此,由参数的输入套接字和用于计算它们的Runnable组成的门可以被视为用于ExcutorServices上的计算的正确构建块.
此方法称为数据流或工作流(如果无法动态创建门).
像Akka这样的Actor框架使用这种方法但是受限制的事实是actor是一个带有单输入套接字的门.
我写了一个真正的数据流库,发布于https://github.com/rfqu/df4j.