2015-05-01 36 views
5

我读了一篇关于fork-join framework in Java 7的好文章,其想法是,使用ForkJoinPoolForkJoinTask,池中的线程可以从其他任务获取子任务,因此它可以使用较少的线程来处理更多的任务。ForkJoinPool和正常的ExecutionService之间的区别?

然后我试着用普通的ExecutorService来做同样的工作,发现我不知道区别,因为当我向池提交一个新任务时,任务将在另一个可用线程上运行。

我可以告诉的唯一区别是,如果我使用ForkJoinPool,我不需要将池传递给任务,因为我可以调用task.fork()使其在另一个线程上运行。但与正常ExecutorService,我必须通过池到任务,或使其成为一个静态,因此在任务内,我可以拨打电话pool.submit(newTask)

我想错过什么吗?

(可以从https://github.com/freewind/fork-join-test/tree/master/src查看居住码)

+2

有几篇文章解释了这两种方法哪一种更适合不同类型的任务。据我记得,Fork-Join池对于递归类型的任务调度来说更好(并且安全)。在任务为同一个ExecutorService生成新任务(正在执行的任务)的情况下,如果ExecutorService池的大小不够大,死机概率很高。尽管叉加入池不是这种情况。 –

回答

5

虽然ForkJoinPool实现ExecutorService,从“正常”执行器概念上不同。

如果您的任务产生更多任务并等待它们完成,您可以轻松看到差异。通过呼叫

executor.invoke(new Task()); // blocks this thread until new task completes 

在一个正常的执行器服务中,等待其他任务完成将阻塞当前线程。有两种可能的结果:如果您的执行程序服务具有固定数量的线程,如果最后一个正在运行的线程等待另一个任务完成,则它可能会死锁。如果您的执行程序按需动态创建新线程,则线程数可能会爆炸,最终会导致数千个可能导致饥饿的线程。

在对面,fork/join框架重用线程同时执行其他任务,这样就不会发生死锁虽然线程的数量是固定的:

new MyForkJoinTask().invoke(); 

所以,如果你有问题你可以递归求解,可以考虑使用ForkJoinPool,因为你可以很容易地实现一个递归级别ForkJoinTask

只需检查示例中正在运行的线程数。