ForkJoin

线程数超过CPU核心数是没有任何意义的【因为要使用CPU密集型运算】

Fork/Join:线程池的实现,体现是分治思想,适用于能够进行任务拆分的 CPU 密集型运算,用于并行计算

任务拆分:将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列都可以用分治思想进行求解

  • Fork/Join 在分治的基础上加入了多线程,把每个任务的分解和合并交给不同的线程来完成,提升了运算效率

  • ForkJoin 使用 ForkJoinPool 来启动,是一个特殊的线程池,默认会创建与 CPU 核心数大小相同的线程池

  • 任务有返回值继承 RecursiveTask,没有返回值继承 RecursiveAction【特殊:不能用Runnable或者Callable了】

 
public static void main(String[] args) {
     ForkJoinPool pool = new ForkJoinPool(4);
     System.out.println(pool.invoke(new MyTask(5)));
     //拆分  5 + MyTask(4) --> 4 + MyTask(3) -->
 }
 ​
 // 1~ n 之间整数的和
 class MyTask extends RecursiveTask<Integer> {
     private int n;
 ​
     public MyTask(int n) {
         this.n = n;
     }
 ​
     @Override
     public String toString() {
         return "MyTask{" + "n=" + n + '}';
     }
 ​
     @Override
     protected Integer compute() {
         // 如果 n 已经为 1,可以求得结果了
         if (n == 1) {
             return n;
         }
         // 将任务进行拆分(fork)
         MyTask t1 = new MyTask(n - 1);
         t1.fork();  //执行计算
         // 合并(join)结果
         int result = n + t1.join(); //获取上面fork的执行结果
         return result;
     }
 }

继续拆分优化:二分法

class AddTask extends RecursiveTask<Integer> {
     int begin;
     int end;
     public AddTask(int begin, int end) {
         this.begin = begin;
         this.end = end;
     }
     
     @Override
     public String toString() {
         return "{" + begin + "," + end + '}';
     }
     
     @Override
     protected Integer compute() {
         // 5, 5
         if (begin == end) {
             return begin;
         }
         // 4, 5  防止多余的拆分  提高效率
         if (end - begin == 1) {
             return end + begin;
         }
         // 1 5
         int mid = (end + begin) / 2; // 3
         AddTask t1 = new AddTask(begin, mid); // 1,3
         t1.fork();
         AddTask t2 = new AddTask(mid + 1, end); // 4,5
         t2.fork();
         int result = t1.join() + t2.join();
         return result;
     }
 }

ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率:

  • 每个线程都维护了一个双端队列,用来存储需要执行的任务

  • 工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行

  • 窃取的必须是最晚的任务,避免和队列所属线程发生竞争,但是队列中只有一个任务时还是会发生竞争

难在如何拆分,后面JDK8就封装到stream的api了,并行流

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值