多线程深入学习--java.util.concurrent工具类二(ForkJoinPool)

1.ForkJoinPool(和执行服务器(ExecutorService)类似,JDK1.7被引入,目的:分叉和合并)

   (1)介绍:ForkJoinPool 在 Java 7 中被引入。它和 ExecutorService 很相似,除了一点不同。

              ForkJoinPool 让我们可以很方便地把任务分裂成几个更小的任务,这些分裂出来的任务也将会提交给 ForkJoinPool。任务可以继续分割成更小的子任务,只要它还能分割。--分叉和合并

   (2)分叉和合并:

               

 

 

                      

                        把自己分割成多个子任务,每个子任务可以由不同的 CPU 并行执行,或者被同一个CPU 上的不同线程执行。
                        备注:只有当给的任务过大,把它分割成几个子任务才有意义。把任务分割成子任务有一定开销,因此对于小型任务,这个分割的消耗可能比每个子任务并发执行的消耗还要大。
                                   什么时候把一个任务分割成子任务是有意义的,这个界限也称作一个阀值。这要看每个任务对有意义阀值的决定。很大程度上取决于它要做的工作的种类。

                         合并:当一个任务将自己分割成若干子任务之后,该任务将进入等待所有子任务的结束之中。一旦子任务执行结束,该任务可以把所有结果合并到同一个结果。

                                   当然,并非所有类型的任务都会返回一个结果。如果这个任务并不返回一个结果,它只需等待所有子任务执行完毕。也就不需要结果的合并啦。

 

   (3)示例:

            1.创建一个 ForkJoinPool

               ForkJoinPool forkJoinPool = new ForkJoinPool(4);

             2.提交任务到 ForkJoinPool

                介绍:就像提交任务到 ExecutorService 那样,把任务提交到 ForkJoinPool。你可以提交两种类型的任务。

                          一种是没有任何返回值的(一个 "行动"),另一种是有返回值的(一个"任务")。这两种类型分别由 RecursiveAction 和 RecursiveTask 表示

                例子(RecursiveAction):

                           import java.util.ArrayList;

                          import java.util.List;

 
                           import java.util.concurrent.RecursiveAction;
 
                          public class MyRecursiveAction extends RecursiveAction {
                                       private long workLoad = 0;
                                       public MyRecursiveAction(long workLoad) {
                                              this.workLoad = workLoad;
                                       } 
                                      @Override
                                      protected void compute() {
                                      //if work is above threshold, break tasks up into smaller tasks
                                      if(this.workLoad > 16) {
                                         System.out.println("Splitting workLoad : " + this.workLoad);
                                         List<MyRecursiveAction> subtasks =new ArrayList<MyRecursiveAction>();
                                         subtasks.addAll(createSubtasks());
                                         for(RecursiveAction subtask : subtasks){
                                                subtask.fork();
                                          }
                                       } else {
                                           System.out.println("Doing workLoad myself: " + this.workLoad);
                                       }
                                   }
                                  private List<MyRecursiveAction> createSubtasks() {
                                   List<MyRecursiveAction> subtasks =new ArrayList<MyRecursiveAction>();
                                   MyRecursiveAction subtask1 = new MyRecursiveAction(this.workLoad / 2);
                                   MyRecursiveAction subtask2 = new MyRecursiveAction(this.workLoad / 2);
                                   subtasks.add(subtask1);
                                   subtasks.add(subtask2);
                                   return subtasks;
                              }
                    }
              例子(RecursiveTask): 
                            import java.util.ArrayList;
                            import java.util.List;
                            import java.util.concurrent.RecursiveTask;
 
                            public class MyRecursiveTask extends RecursiveTask<Long> {
                                  private long workLoad = 0;
 
                                  public MyRecursiveTask(long workLoad) {
                                         this.workLoad = workLoad;
 
                                  }
 
                                 protected Long compute() {
 
                                 //if work is above threshold, break tasks up into smaller tasks
                                 if(this.workLoad > 16) {
                                          System.out.println("Splitting workLoad : " + this.workLoad);
                                           List<MyRecursiveTask> subtasks =new ArrayList<MyRecursiveTask>();
 
                                           subtasks.addAll(createSubtasks());
                                           for(MyRecursiveTask subtask : subtasks){
                                                   subtask.fork();
                                            }
                                            long result = 0;
                                            for(MyRecursiveTask subtask : subtasks) {
                                                     result += subtask.join();
                                             }
                                             return result;
                                         } else {
                                              System.out.println("Doing workLoad myself: " + this.workLoad);
                                              return workLoad * 3;
                                          }
                                    }
                                   private List<MyRecursiveTask> createSubtasks() {
                                   List<MyRecursiveTask> subtasks =new ArrayList<MyRecursiveTask>();
                                   MyRecursiveTask subtask1 = new MyRecursiveTask(this.workLoad / 2);
                                   MyRecursiveTask subtask2 = new MyRecursiveTask(this.workLoad / 2);
                                   subtasks.add(subtask1);
                                   subtasks.add(subtask2);
                                    return subtasks;
                               }
                           }
                 
               3.除了有一个结果返回之外,这个示例和 RecursiveAction 的例子很像。MyRecursiveTask 类继承自 RecursiveTask<Long>,这也就意味着它将返回一个 Long 类型的结果。
                  MyRecursiveTask 示例也会将工作分割为子任务,并通过 fork() 方法对这些子任务计划执行。
                  此外,本示例还通过调用每个子任务的 join() 方法收集它们返回的结果。子任务的结果随后被合并到一个更大的结果,并最终将其返回。对于不同级别的递归,这种子任务的结果合并可能会发生递归。
                  你可以这样规划一个 RecursiveTask:
                           MyRecursiveTask myRecursiveTask = new MyRecursiveTask(128);
                           long mergedResult = forkJoinPool.invoke(myRecursiveTask);
                           System.out.println("mergedResult = " + mergedResult);
                           注意是如何通过 ForkJoinPool.invoke() 方法的调用来获取最终执行结果的。
 
 
备注:这种拆分任务必定存在问题,学习没遇到,可以看看别人的例子
参考:https://blog.csdn.net/hotdust/article/details/71480762?utm_source=blogkpcl4
           java_util_concurrent_user_guide.pdf
           https://blog.csdn.net/u011385186/article/details/79135437
           https://blog.csdn.net/dichengyan0013/article/details/102347095
                
posted @ 2020-08-14 15:56  小窝蜗  阅读(215)  评论(0编辑  收藏  举报