@boothsun
2018-03-10T09:40:16.000000Z
字数 1967
阅读 1870
Java多线程
Fork/Join框架是Java 7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。那么,为什么需要使用工作窃取算法呢?假如我们需要做一个比较大的任务,可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应。比如A线程负责处理A队列里的任务。但是,有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。
工作窃取的运行流程下图所示:

ForkJoinPool是ForkJoin框架中的任务调度器,和ThreadPoolExecutor一样实现了自己的线程池,提供了三种调度子任务的方法:
我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制。通常情况下,我们不需要直接继承ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了以下两个子类。
public class ForkJoinTest extends RecursiveTask<Long> {private static final long MAX = 1000000000L;private static final long THRESHOLD = 1000L;private long start;private long end;public ForkJoinTest(long start, long end) {this.start = start;this.end = end;}public static void main(String[] args) throws Exception{System.out.println("--------------------");Thread.sleep(10 * 1000L);testForkJoin();}private static void testForkJoin() {System.out.println("testForkJoin");long start = System.currentTimeMillis();ForkJoinPool forkJoinPool = new ForkJoinPool();Long sum = forkJoinPool.invoke(new ForkJoinTest(1, MAX));System.out.println(sum);System.out.println(System.currentTimeMillis() - start + "ms");}@Overrideprotected Long compute() {long sum = 0;if (end - start <= THRESHOLD) {for (long i = start; i <= end; i++) {sum += i;}return sum;} else {long mid = (start + end) / 2;ForkJoinTest task1 = new ForkJoinTest(start, mid);ForkJoinTest task2 = new ForkJoinTest(mid + 1, end);invokeAll(task1,task2);return task1.join() + task2.join();}}}
网文关于正确使用Fork/JOIN框架:
