ForkJoinPool有一个特点是work stealing。每个工作线程都有自己的工作队列,这是使用deque来实现的。当一个任务划分一个新线程时,它将自己推到 deque 的头部。当一个任务执行与另一个未完成任务的合并操作时,它会将另一个任务推到队列头部并执行,而不会休眠以等待另一任务完成(像 Thread.join() 的操作一样)。当线程的任务队列为空,它将尝试从另一个线程的 deque 的尾部 窃取另一个任务。如果我们用传统的ThreadPoolExecutor则比较难用上work stealing的技术。
Fork/Join 模式有自己的适用范围。如果一个应用能被分解成多个子任务,并且组合多个子任务的结果就能够获得最终的答案,那么这个应用就适合用 Fork/Join 模式来解决。
ForkJoinPool核心的添加是新的ForkJoinPool执行者,专门执行实现了ForkJoinTask接口的实例。ForkJoinTask对象支持创建子任务来等待子任务完成。有了这些清晰的语义,当一个任务正在等待另一个任务完成并且有待执行的任务时,executor就能够通过”偷取”任务,在内部的线程池里分发任务。
ForkJoinTask对象主要有两个重要的方法:
- fork()方法允许ForkJoinTask任务异步执行,也允许一个新的ForkJoinTask从存在的ForkJoinTask中被启动。
- 反过来, join()方法允许一个ForkJoinTask等待另一个ForkJoinTask执行完成。
有两种类型的ForkJoinTask的定义:
- RecursiveAction的实例代表执行没有返回结果。
- 相反,RecursiveTask会有返回值。
通常,RecursiveTask是首选的,因为大部分分而治之的算法会在数据集上计算后返回结果。对于任务的执行,不同的同步和异步选项是可选的,这样就可以实现复杂的模式。
注意点:ForkJoinTask对应的fork/join任务应该是纯内存算法,而没有I/O操作。此外,应该尽可能避免通过共享状态来进行任务间的通信,因为这通常意味着加锁会被执行。理想情况下,仅当一个任务fork另一个任务或一个任务join另一个任务时才进行任务通信。ForkJoinPool系统介绍:http://ifeve.com/fork-and-join-java/
Java线程池概述:http://blog.csdn.net/dm_vincent/article/details/39505977
详解介绍了线程池的线程数目如何设置以及普通线程池和ForkJoinPool的区别的使用场景。
ForkJoinPool简单源码解析:http://blog.csdn.net/aesop_wubo/article/details/10300273
ForkJoinPool介绍:
http://www.ibm.com/developerworks/cn/java/j-jtp11137.html
http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html
ForkJoinPool介绍:
http://www.ibm.com/developerworks/cn/java/j-jtp11137.html
http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html
没有评论:
发表评论