现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机、多核处理器已被广泛应用。在未来,处理器的核心数将会发展的越来越多。

虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这种多核CPU做好准备,因此并不能很好地利用多核CPU的性能优势。

为了充分利用多CPU、多核CPU的性能优势,级软基软件系统应该可以充分“挖掘”每个CPU的计算能力,决不能让某个CPU处于“空闲”状态。为此,可以考虑把一个任务拆分成多个“小任务”,把多个"小任务"放到多个处理器核心上并行执行。当多个“小任务”执行完成之后,再将这些执行结果合并起来即可

如下面的示意图所示:

第一步分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停的分割,直到分割出的子任务足够小。

第二步执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。

Java提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合成总的计算结果。

ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池。ForkJoinPool提供了如下两个常用的构造器。

public ForkJoinPool(int parallelism):创建一个包含parallelism个并行线程的ForkJoinPool public ForkJoinPool() :以Runtime.getRuntime().availableProcessors()的返回值作为parallelism来创建ForkJoinPool

创建ForkJoinPool实例后,可以钓鱼ForkJoinPool的submit(ForkJoinTask task)或者invoke(ForkJoinTask task)来执行指定任务。其中ForkJoinTask代表一个可以并行、合并的任务。ForkJoinTask是一个抽象类,它有两个抽象子类:RecursiveAction和RecursiveTask。

RecursiveTask代表有返回值的任务 RecursiveAction代表没有返回值的任务。

一、RecursiveAction

下面以一个没有返回值的大任务为例,介绍一下RecursiveAction的用法。

大任务是:打印0-200的数值。

小任务是:每次只能打印50个数值。

  1. import java.util.concurrent.ForkJoinPool;
  2. import java.util.concurrent.RecursiveAction;
  3. import java.util.concurrent.TimeUnit;
  4. //RecursiveAction为ForkJoinTask的抽象子类,没有返回值的任务
  5. class PrintTask extends RecursiveAction {
  6. // 每个"小任务"最多只打印50个数
  7. private static final int MAX = 50;
  8. private int start;
  9. private int end;
  10. PrintTask(int start, int end) {
  11. this.start = start;
  12. this.end = end;
  13. }
  14. @Override
  15. protected void compute() {
  16. // 当end-start的值小于MAX时候,开始打印
  17. if ((end - start) < MAX) {
  18. for (int i = start; i < end; i++) {
  19. System.out.println(Thread.currentThread().getName() + "的i值:"
  20. + i);
  21. }
  22. } else {
  23. // 将大任务分解成两个小任务
  24. int middle = (start + end) / 2;
  25. PrintTask left = new PrintTask(start, middle);
  26. PrintTask right = new PrintTask(middle, end);
  27. // 并行执行两个小任务
  28. left.fork();
  29. right.fork();
  30. }
  31. }
  32. }
  33. public class ForkJoinPoolTest {
  34. /**
  35. * @param args
  36. * @throws Exception
  37. */
  38. public static void main(String[] args) throws Exception {
  39. // 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
  40. ForkJoinPool forkJoinPool = new ForkJoinPool();
  41. // 提交可分解的PrintTask任务
  42. forkJoinPool.submit(new PrintTask(0, 200));
  43. forkJoinPool.awaitTermination(2, TimeUnit.SECONDS);//阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束
  44. // 关闭线程池
  45. forkJoinPool.shutdown();
  46. }
  47. }

复制代码

运行结果如下:

  1. ForkJoinPool-1-worker-2的i值:75
  2. ForkJoinPool-1-worker-2的i值:76
  3. ForkJoinPool-1-worker-2的i值:77
  4. ForkJoinPool-1-worker-2的i值:78
  5. ForkJoinPool-1-worker-2的i值:79
  6. ForkJoinPool-1-worker-2的i值:80
  7. ForkJoinPool-1-worker-2的i值:81
  8. ForkJoinPool-1-worker-2的i值:82
  9. ForkJoinPool-1-worker-2的i值:83
  10. ForkJoinPool-1-worker-2的i值:84
  11. ForkJoinPool-1-worker-2的i值:85
  12. ForkJoinPool-1-worker-2的i值:86
  13. ForkJoinPool-1-worker-2的i值:87
  14. ForkJoinPool-1-worker-2的i值:88
  15. ForkJoinPool-1-worker-2的i值:89
  16. ForkJoinPool-1-worker-2的i值:90
  17. ForkJoinPool-1-worker-2的i值:91
  18. ForkJoinPool-1-worker-2的i值:92
  19. ForkJoinPool-1-worker-2的i值:93
  20. ForkJoinPool-1-worker-2的i值:94
  21. ForkJoinPool-1-worker-2的i值:95
  22. ForkJoinPool-1-worker-2的i值:96
  23. ForkJoinPool-1-worker-2的i值:97
  24. ForkJoinPool-1-worker-2的i值:98
  25. ForkJoinPool-1-worker-2的i值:99
  26. ForkJoinPool-1-worker-2的i值:50
  27. ForkJoinPool-1-worker-2的i值:51
  28. ForkJoinPool-1-worker-2的i值:52
  29. ForkJoinPool-1-worker-2的i值:53
  30. ForkJoinPool-1-worker-2的i值:54
  31. ForkJoinPool-1-worker-2的i值:55
  32. ForkJoinPool-1-worker-2的i值:56
  33. ForkJoinPool-1-worker-2的i值:57
  34. ForkJoinPool-1-worker-2的i值:58
  35. ForkJoinPool-1-worker-2的i值:59
  36. ForkJoinPool-1-worker-2的i值:60
  37. ForkJoinPool-1-worker-2的i值:61
  38. ForkJoinPool-1-worker-2的i值:62
  39. ForkJoinPool-1-worker-2的i值:63
  40. ForkJoinPool-1-worker-2的i值:64
  41. ForkJoinPool-1-worker-2的i值:65
  42. ForkJoinPool-1-worker-2的i值:66
  43. ForkJoinPool-1-worker-2的i值:67
  44. ForkJoinPool-1-worker-2的i值:68
  45. ForkJoinPool-1-worker-2的i值:69
  46. ForkJoinPool-1-worker-1的i值:175
  47. ForkJoinPool-1-worker-1的i值:176
  48. ForkJoinPool-1-worker-1的i值:177
  49. ForkJoinPool-1-worker-1的i值:178
  50. ForkJoinPool-1-worker-1的i值:179
  51. ForkJoinPool-1-worker-1的i值:180
  52. ForkJoinPool-1-worker-1的i值:181
  53. ForkJoinPool-1-worker-1的i值:182
  54. ForkJoinPool-1-worker-1的i值:183
  55. ForkJoinPool-1-worker-1的i值:184
  56. ForkJoinPool-1-worker-1的i值:185
  57. ForkJoinPool-1-worker-1的i值:186
  58. ForkJoinPool-1-worker-1的i值:187
  59. ForkJoinPool-1-worker-1的i值:188
  60. ForkJoinPool-1-worker-1的i值:189
  61. ForkJoinPool-1-worker-1的i值:190
  62. ForkJoinPool-1-worker-1的i值:191
  63. ForkJoinPool-1-worker-1的i值:192
  64. ForkJoinPool-1-worker-1的i值:193
  65. ForkJoinPool-1-worker-1的i值:194
  66. ForkJoinPool-1-worker-1的i值:195
  67. ForkJoinPool-1-worker-1的i值:196
  68. ForkJoinPool-1-worker-1的i值:197
  69. ForkJoinPool-1-worker-1的i值:198
  70. ForkJoinPool-1-worker-1的i值:199
  71. ForkJoinPool-1-worker-1的i值:150
  72. ForkJoinPool-1-worker-1的i值:151
  73. ForkJoinPool-1-worker-1的i值:152
  74. ForkJoinPool-1-worker-1的i值:153
  75. ForkJoinPool-1-worker-1的i值:154
  76. ForkJoinPool-1-worker-1的i值:155
  77. ForkJoinPool-1-worker-1的i值:156
  78. ForkJoinPool-1-worker-1的i值:157
  79. ForkJoinPool-1-worker-1的i值:158
  80. ForkJoinPool-1-worker-1的i值:159
  81. ForkJoinPool-1-worker-1的i值:160
  82. ForkJoinPool-1-worker-1的i值:161
  83. ForkJoinPool-1-worker-1的i值:162
  84. ForkJoinPool-1-worker-1的i值:163
  85. ForkJoinPool-1-worker-1的i值:164
  86. ForkJoinPool-1-worker-1的i值:165
  87. ForkJoinPool-1-worker-1的i值:166
  88. ForkJoinPool-1-worker-1的i值:167
  89. ForkJoinPool-1-worker-1的i值:168
  90. ForkJoinPool-1-worker-1的i值:169
  91. ForkJoinPool-1-worker-1的i值:170
  92. ForkJoinPool-1-worker-1的i值:171
  93. ForkJoinPool-1-worker-1的i值:172
  94. ForkJoinPool-1-worker-1的i值:173
  95. ForkJoinPool-1-worker-1的i值:174
  96. ForkJoinPool-1-worker-1的i值:125
  97. ForkJoinPool-1-worker-1的i值:126
  98. ForkJoinPool-1-worker-1的i值:127
  99. ForkJoinPool-1-worker-1的i值:128
  100. ForkJoinPool-1-worker-1的i值:129
  101. ForkJoinPool-1-worker-1的i值:130
  102. ForkJoinPool-1-worker-1的i值:131
  103. ForkJoinPool-1-worker-1的i值:132
  104. ForkJoinPool-1-worker-1的i值:133
  105. ForkJoinPool-1-worker-1的i值:134
  106. ForkJoinPool-1-worker-1的i值:135
  107. ForkJoinPool-1-worker-1的i值:136
  108. ForkJoinPool-1-worker-1的i值:137
  109. ForkJoinPool-1-worker-1的i值:138
  110. ForkJoinPool-1-worker-1的i值:139
  111. ForkJoinPool-1-worker-1的i值:140
  112. ForkJoinPool-1-worker-1的i值:141
  113. ForkJoinPool-1-worker-1的i值:142
  114. ForkJoinPool-1-worker-1的i值:143
  115. ForkJoinPool-1-worker-1的i值:144
  116. ForkJoinPool-1-worker-1的i值:145
  117. ForkJoinPool-1-worker-1的i值:146
  118. ForkJoinPool-1-worker-1的i值:147
  119. ForkJoinPool-1-worker-1的i值:148
  120. ForkJoinPool-1-worker-1的i值:149
  121. ForkJoinPool-1-worker-1的i值:100
  122. ForkJoinPool-1-worker-1的i值:101
  123. ForkJoinPool-1-worker-1的i值:102
  124. ForkJoinPool-1-worker-1的i值:103
  125. ForkJoinPool-1-worker-1的i值:104
  126. ForkJoinPool-1-worker-1的i值:105
  127. ForkJoinPool-1-worker-1的i值:106
  128. ForkJoinPool-1-worker-1的i值:107
  129. ForkJoinPool-1-worker-1的i值:108
  130. ForkJoinPool-1-worker-1的i值:109
  131. ForkJoinPool-1-worker-1的i值:110
  132. ForkJoinPool-1-worker-1的i值:111
  133. ForkJoinPool-1-worker-1的i值:112
  134. ForkJoinPool-1-worker-1的i值:113
  135. ForkJoinPool-1-worker-1的i值:114
  136. ForkJoinPool-1-worker-1的i值:115
  137. ForkJoinPool-1-worker-1的i值:116
  138. ForkJoinPool-1-worker-1的i值:117
  139. ForkJoinPool-1-worker-1的i值:118
  140. ForkJoinPool-1-worker-1的i值:119
  141. ForkJoinPool-1-worker-1的i值:120
  142. ForkJoinPool-1-worker-1的i值:121
  143. ForkJoinPool-1-worker-1的i值:122
  144. ForkJoinPool-1-worker-1的i值:123
  145. ForkJoinPool-1-worker-1的i值:124
  146. ForkJoinPool-1-worker-1的i值:25
  147. ForkJoinPool-1-worker-1的i值:26
  148. ForkJoinPool-1-worker-1的i值:27
  149. ForkJoinPool-1-worker-1的i值:28
  150. ForkJoinPool-1-worker-1的i值:29
  151. ForkJoinPool-1-worker-1的i值:30
  152. ForkJoinPool-1-worker-1的i值:31
  153. ForkJoinPool-1-worker-1的i值:32
  154. ForkJoinPool-1-worker-1的i值:33
  155. ForkJoinPool-1-worker-1的i值:34
  156. ForkJoinPool-1-worker-1的i值:35
  157. ForkJoinPool-1-worker-1的i值:36
  158. ForkJoinPool-1-worker-1的i值:37
  159. ForkJoinPool-1-worker-1的i值:38
  160. ForkJoinPool-1-worker-1的i值:39
  161. ForkJoinPool-1-worker-1的i值:40
  162. ForkJoinPool-1-worker-1的i值:41
  163. ForkJoinPool-1-worker-1的i值:42
  164. ForkJoinPool-1-worker-1的i值:43
  165. ForkJoinPool-1-worker-1的i值:44
  166. ForkJoinPool-1-worker-1的i值:45
  167. ForkJoinPool-1-worker-1的i值:46
  168. ForkJoinPool-1-worker-1的i值:47
  169. ForkJoinPool-1-worker-1的i值:48
  170. ForkJoinPool-1-worker-1的i值:49
  171. ForkJoinPool-1-worker-1的i值:0
  172. ForkJoinPool-1-worker-1的i值:1
  173. ForkJoinPool-1-worker-1的i值:2
  174. ForkJoinPool-1-worker-1的i值:3
  175. ForkJoinPool-1-worker-1的i值:4
  176. ForkJoinPool-1-worker-1的i值:5
  177. ForkJoinPool-1-worker-1的i值:6
  178. ForkJoinPool-1-worker-1的i值:7
  179. ForkJoinPool-1-worker-1的i值:8
  180. ForkJoinPool-1-worker-1的i值:9
  181. ForkJoinPool-1-worker-1的i值:10
  182. ForkJoinPool-1-worker-1的i值:11
  183. ForkJoinPool-1-worker-1的i值:12
  184. ForkJoinPool-1-worker-1的i值:13
  185. ForkJoinPool-1-worker-1的i值:14
  186. ForkJoinPool-1-worker-1的i值:15
  187. ForkJoinPool-1-worker-1的i值:16
  188. ForkJoinPool-1-worker-1的i值:17
  189. ForkJoinPool-1-worker-1的i值:18
  190. ForkJoinPool-1-worker-1的i值:19
  191. ForkJoinPool-1-worker-1的i值:20
  192. ForkJoinPool-1-worker-1的i值:21
  193. ForkJoinPool-1-worker-1的i值:22
  194. ForkJoinPool-1-worker-1的i值:23
  195. ForkJoinPool-1-worker-1的i值:24
  196. ForkJoinPool-1-worker-2的i值:70
  197. ForkJoinPool-1-worker-2的i值:71
  198. ForkJoinPool-1-worker-2的i值:72
  199. ForkJoinPool-1-worker-2的i值:73
  200. ForkJoinPool-1-worker-2的i值:74

复制代码

从上面结果来看,ForkJoinPool启动了两个线程来执行这个打印任务,这是因为笔者的计算机的CPU是双核的。不仅如此,读者可以看到程序虽然打印了0-199这两百个数字,但是并不是连续打印的,这是因为程序将这个打印任务进行了分解,分解后的任务会并行执行,所以不会按顺序从0打印 到199

二、RecursiveTask

下面以一个有返回值的大任务为例,介绍一下RecursiveTask的用法。

大任务是:计算随机的100个数字的和。

小任务是:每次只能20个数值的和。

  1. import java.util.Random;
  2. import java.util.concurrent.ForkJoinPool;
  3. import java.util.concurrent.Future;
  4. import java.util.concurrent.RecursiveTask;
  5. //RecursiveTask为ForkJoinTask的抽象子类,有返回值的任务
  6. class SumTask extends RecursiveTask<Integer> {
  7. // 每个"小任务"最多只打印50个数
  8. private static final int MAX = 20;
  9. private int arr[];
  10. private int start;
  11. private int end;
  12. SumTask(int arr[], int start, int end) {
  13. this.arr = arr;
  14. this.start = start;
  15. this.end = end;
  16. }
  17. @Override
  18. protected Integer compute() {
  19. int sum = 0;
  20. // 当end-start的值小于MAX时候,开始打印
  21. if ((end - start) < MAX) {
  22. for (int i = start; i < end; i++) {
  23. sum += arr[i];
  24. }
  25. return sum;
  26. } else {
  27. System.err.println("=====任务分解======");
  28. // 将大任务分解成两个小任务
  29. int middle = (start + end) / 2;
  30. SumTask left = new SumTask(arr, start, middle);
  31. SumTask right = new SumTask(arr, middle, end);
  32. // 并行执行两个小任务
  33. left.fork();
  34. right.fork();
  35. // 把两个小任务累加的结果合并起来
  36. return left.join() + right.join();
  37. }
  38. }
  39. }
  40. public class ForkJoinPoolTest2 {
  41. /**
  42. * @param args
  43. * @throws Exception
  44. */
  45. public static void main(String[] args) throws Exception {
  46. int arr[] = new int[100];
  47. Random random = new Random();
  48. int total = 0;
  49. // 初始化100个数字元素
  50. for (int i = 0; i < arr.length; i++) {
  51. int temp = random.nextInt(100);
  52. // 对数组元素赋值,并将数组元素的值添加到total总和中
  53. total += (arr[i] = temp);
  54. }
  55. System.out.println("初始化时的总和=" + total);
  56. // 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
  57. ForkJoinPool forkJoinPool = new ForkJoinPool();
  58. // 提交可分解的PrintTask任务
  59. Future<Integer> future = forkJoinPool.submit(new SumTask(arr, 0,
  60. arr.length));
  61. System.out.println("计算出来的总和=" + future.get());
  62. // 关闭线程池
  63. forkJoinPool.shutdown();
  64. }
  65. }

复制代码

计算结果如下:

  1. 初始化时的总和=4283
  2. =====任务分解======
  3. =====任务分解======
  4. =====任务分解======
  5. =====任务分解======
  6. =====任务分解======
  7. =====任务分解======
  8. =====任务分解======
  9. 计算出来的总和=4283

复制代码

从上面结果来看,ForkJoinPool将任务分解了7次,程序通过SumTask计算出来的结果,和初始化数组时统计出来的总和是相等的,这表明计算结果一切正常。

Java使用Fork/Join框架来并行执行任务的更多相关文章

  1. 我的Java开发学习之旅------>Java使用Fork/Join框架来并行执行任务

    现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多. 虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这 ...

  2. Java并发——Fork/Join框架

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...

  3. Java 7 Fork/Join 框架

    在 Java7引入的诸多新特性中,Fork/Join 框架无疑是重要的一项.JSR166旨在标准化一个实质上可扩展的框架,以将并行计算的通用工具类组织成一个类似java.util中Collection ...

  4. Java并发——Fork/Join框架与ForkJoinPool

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...

  5. Java Fork/Join 框架

    简介 从JDK1.7开始,Java提供Fork/Join框架用于并行执行任务,它的思想就是讲一个大任务分割成若干小任务,最终汇总每个小任务的结果得到这个大任务的结果. 这种思想和MapReduce很像 ...

  6. Java并发编程(07):Fork/Join框架机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Fork/Join框架 Java提供Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务 ...

  7. 013-多线程-基础-Fork/Join框架、parallelStream讲解

    一.概述 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 它同ThreadPoolExecut ...

  8. Fork/Join框架详解

    Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.Fork/Join框架要完成两件事情: 1.任务分 ...

  9. 初步了解Fork/Join框架

    框架介绍 Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个子任务,最终汇总每个子任务的执行结果以得到大任务结果的框架.Fork/Join框架要完成两件事 ...

随机推荐

  1. 了解JavaScript 对象属性的标签

    对象属性的标签 value(属性值), writable(属性可写), enumerable(属性可枚举), configurable(属性可配置), 这些属性标签使对象所持有的属性体现出不同的特性, ...

  2. vim使用笔记

    vim的配置文件.vimrc  一般有2个位置 1是在/目录下 2是在-目录下 如果在-目录下有了配置文件 那么将不去读取/目录下面的配置文件 如果你不知道现在使用的vim 使用的是哪个目录下面的配置 ...

  3. 在windows系统下,在终端快速打开某个路径

    进了一个文件夹,要在这个文件夹上直接打开CMD,而不是在系统C盘打开CMD 1) 在此文件夹窗口内空白区域右键单击(需要同时按住Shift),从菜单中选择"在此处打开命令行窗口"的项:2) 快捷键Al ...

  4. java简单模拟生产者消费者问题

    本文来自:http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html 引言 生产者和消费者问题是线程模型中的经典问题:生产者和 ...

  5. java中可定制的序列化过程 writeObject与readObject

    来源于:[http://bluepopopo.iteye.com/blog/486548] 什么是writeObject 和readObject?可定制的序列化过程 这篇文章很直接,简单易懂.尝试着翻 ...

  6. nginx+php-fpm+mysql分离部署详解

    相信大家将这三者部署到同一台主机应该已经不陌生了,今天在这里,给大家演示一下如何将三者部署到三台主机上. 实验系统:CentOS 6.6_x86_64 实验前提:大部分软件使用编译安装,请提前准备好编 ...

  7. uva 129 krypton factors ——yhx

     Krypton Factor  You have been employed by the organisers of a Super Krypton Factor Contest in which ...

  8. canvas贝塞尔曲线 - 2

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAugAAAH7CAIAAAARkv1vAAAgAElEQVR4nOy9e5Ab13ngO7Z37dlsaM

  9. cf Round 633

    A.Rebus(思维题) 给出一个这种形式的表达式 ? + ? - ? + ? = n.要求用1-n的数字填充疑问号使等式成立,如果不存在这样的方式,则输出不可能.存在则输出任意的方式. 移项可以变成 ...

  10. 【Kindle】pdf转mobi适合kindle查看格式

    pdf转mobi适合kindle查看格式 1.用到软件:福昕风腾PDF套件,切白边,PDF-Viewer,导出png图片ChainLP,图片转换为mobi文件<期间要下载kindlegen.ex ...