ForkJoinPool 和普通 ExecutionService 的区别?
Difference between ForkJoinPool and normal ExecutionService?
我读了一篇关于 fork-join framework in Java 7 的很棒的文章,其想法是,使用 ForkJoinPool
和 ForkJoinTask
,池中的线程可以从其他任务中获取子任务, 因此它能够使用更少的线程来处理更多的任务。
然后我尝试使用普通的ExecutorService
做同样的工作,发现我无法区分,因为当我向池中提交一个新任务时,任务将是运行 在另一个可用线程上。
我能说的唯一区别是如果我使用 ForkJoinPool
,我不需要将池传递给任务,因为我可以调用 task.fork()
使它成为 运行在另一个线程上。但是对于正常的 ExecutorService
,我必须将池传递给任务,或者使其成为静态的,所以在任务内部,我可以调用 pool.submit(newTask)
我错过了什么吗?
(可以查看https://github.com/freewind/fork-join-test/tree/master/src的直播代码)
虽然 ForkJoinPool
实现了 ExecutorService
,但它在概念上不同于 'normal' 执行器。
如果您的任务产生更多任务并等待它们完成,您可以很容易地看出差异,例如通过调用
executor.invoke(new Task()); // blocks this thread until new task completes
在普通的执行器服务中,等待其他任务完成会阻塞当前线程。有两种可能的结果:如果您的执行程序服务具有 固定数量的线程 ,如果最后一个 运行 线程等待另一个任务完成,它可能会死锁。如果您的执行程序按需动态创建新线程,线程数量可能会激增,您最终会拥有数千个线程,这可能会导致饥饿。
相反,fork/join框架在执行其他任务的同时重用了线程,所以即使线程数固定也不会死锁:
new MyForkJoinTask().invoke();
因此,如果您遇到可以递归解决的问题,请考虑使用 ForkJoinPool
,因为您可以轻松实现一级递归,如 ForkJoinTask
.
只需检查示例中 运行 个线程的数量。
我读了一篇关于 fork-join framework in Java 7 的很棒的文章,其想法是,使用 ForkJoinPool
和 ForkJoinTask
,池中的线程可以从其他任务中获取子任务, 因此它能够使用更少的线程来处理更多的任务。
然后我尝试使用普通的ExecutorService
做同样的工作,发现我无法区分,因为当我向池中提交一个新任务时,任务将是运行 在另一个可用线程上。
我能说的唯一区别是如果我使用 ForkJoinPool
,我不需要将池传递给任务,因为我可以调用 task.fork()
使它成为 运行在另一个线程上。但是对于正常的 ExecutorService
,我必须将池传递给任务,或者使其成为静态的,所以在任务内部,我可以调用 pool.submit(newTask)
我错过了什么吗?
(可以查看https://github.com/freewind/fork-join-test/tree/master/src的直播代码)
虽然 ForkJoinPool
实现了 ExecutorService
,但它在概念上不同于 'normal' 执行器。
如果您的任务产生更多任务并等待它们完成,您可以很容易地看出差异,例如通过调用
executor.invoke(new Task()); // blocks this thread until new task completes
在普通的执行器服务中,等待其他任务完成会阻塞当前线程。有两种可能的结果:如果您的执行程序服务具有 固定数量的线程 ,如果最后一个 运行 线程等待另一个任务完成,它可能会死锁。如果您的执行程序按需动态创建新线程,线程数量可能会激增,您最终会拥有数千个线程,这可能会导致饥饿。
相反,fork/join框架在执行其他任务的同时重用了线程,所以即使线程数固定也不会死锁:
new MyForkJoinTask().invoke();
因此,如果您遇到可以递归解决的问题,请考虑使用 ForkJoinPool
,因为您可以轻松实现一级递归,如 ForkJoinTask
.
只需检查示例中 运行 个线程的数量。