为了提高大量任务的执行效率,一般会使用线程池(ThreadPoolExecutor)。但是考虑到某些单任务本身就可以继续拆分并发执行(例如对1000W个数据进行排序可以使用分治思想),如何更好地提高这些任务的并发效率将成为一个问题。
Fork/Join模式解决了任务更小粒度拆分的问题,我们可以将一个任务拆分成多个可并发执行的部分,最后再对各个子任务的结果进行汇总,得到最终执行结果。
1.Fork/Join模式下的线程池:ForkJoinPool
ForkJoinPool中的每个worker线程都有自己的workQueue(而ThreadPoolExecutor是所有worker线程都从1个公共的工作队列中取任务)。当某个worker线程的队列任务都完成后,这个空闲的worker线程会从其它线程的工作队列中偷一个任务执行(也称work-stealing),以提高并发效率。
1.1 ForkJoinPool的实例化
|
2.任务的封装:ForkJoinTask
ForkJoinTask代表在ForkJoinPool中运行的任务。
2.1 ForkJoinTask的子类
2.2 fork方法
fork方法是把当前的ForkJoinTask(即子任务)交由ForkJoinPool异步执行。 若当前线程是ForkJoinWorkerThread,则ForkJoinTask会被自动交由所在的ForkJoinPool执行;否则交由静态ForkJoinPool执行。所以只要指定了第一个父任务所在的ForkJoinPool,就可以确保其子任务调用fork方法后也一定在这个ForkJoinPool中被执行。所以第一个任务必须指定ForkJoinPool:
2.3 invoke方法开始执行任务,如果必要,等待计算完成(阻塞等待)。
2.4 invokeAll方法
从源码可以看出,利用invokeAll方法执行多个子任务可以有效利用当前worker线程,避免线程的过多创建。
2.5 join方法返回任务的执行结果(阻塞等待)
2.6 举例(一个compute方法的实现):
|
3.ForkJoinTask测试
|
输出结果:
cpu核数:4,数组长度:10000 Fork/Join模拟累加计算结束,耗时3771ms 单线程模拟累加计算结束,耗时10002ms |