Java7之线程池ForkJoinPool

本文深入探讨Java并发编程中ForkJoinPool的原理与使用方法,通过示例代码展示如何利用ForkJoinPool提高程序效率。同时,介绍了ForkJoinTask的实现方式与常用方法,以及如何在实际项目中应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

许多情况下,在一个程序中使用多线程是有益处的,可以大大提高程序的效率,多线程主要有以下3个优点1,资源利用率更好2,程序设计在某些情况下更简单3,程序响应更快。当然凡事有利就有弊,多线程也会使程序的开发,维护及调试更加复杂,当然如果我们能够扬长避短,在正确的场合下使用多线程,那么它将成为我们程序中开发的利器。 


Java一直以来,对多线程的开发支持比较良好,特别在JDK5,6后引入的java.util.concurrent包,使用多线程的开发变的更加容易,这个包里面大部分的API都是更进一步的封装,作为开发者,我们只需熟悉它怎么使用,就能够很轻松的上手,当然如果你想完全搞懂它,那么就需要读读那些优秀的源码了。 

ForkJoinPool这个类是JDK7后新增的线程池,很适合在单机多核的PC上部署多线程程序,ForkJoinPool使用的分而治之的思想,这一点与当前很火的大数据处理框架Hadoop的map/reduce思想非常类似,但是他们的使用场合却不一样,ForkJoinPool适合在一台PC多核CPU上运行,而hadoop则适合在分布式环境中进行大规模集群部署。 

Fork/Join 模式有自己的适用范围。如果一个应用能被分解成多个子任务,并且组合多个子任务的结果就能够获得最终的答案,那么这个应用就适合用 Fork/Join 模式来解决. 

ForkJoinPool使用的工作窃取的方式能够在最大方式上充分利用CPU的资源,一般流程是fork分解,join结合。本质是将一个任务分解成多个子任务,每个子任务用单独的线程去处理,主要几个常用方法有 
fork( ForkJoinTask)异步执行一个线程
join( ForkJoinTask)等待任务完成并返回执行结果
execute( ForkJoinTask)执行不带返回值的任务
submit( ForkJoinTask)执行带返回值的任务
invoke( ForkJoinTask)执行指定的任务,等待完成,返回结果。
invokeAll(ForkJoinTask)执行指定的任务,等待完成,返回结果。
shutdown()执行此方法之后,ForkJoinPool 不再接受新的任务,但是已经提交的任务可以继续执行。如果希望立刻停止所有的任务,可以尝试 shutdownNow() 方法。
awaitTermination(int, TimeUnit.SECONDS)阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束。
compute()执行任务的具体方法
Runtime.getRuntime().availableProcessors()获取CPU个数的方法

关于上表中的ForkJoinTask是一个抽象类,代表一个可以fork与join的任务. ,它还有2个抽象子类:RecursiveAcion和RecursiveTask.其中RecursiveTask代表有泛型返回值的任务.而RecursiveAction代表没有返回值. 


下面给出测试代码 

Java代码  收藏代码
  1. package com.demo;  
  2.   
  3. import java.util.concurrent.RecursiveAction;  
  4.   
  5. /** 
  6.  *  
  7.  * 继承RecursiveAction来实现可分解的任务 
  8.  * 注意无返回值 
  9.  *  
  10.  * **/  
  11.   
  12. public class PrintTask extends RecursiveAction {  
  13.    
  14.     //每个小任务,最多只打印50个数  
  15.     private static final int threshold=50;  
  16.     //打印任务的开始  
  17.     private int start;  
  18.     //打印任务的结束  
  19.     private int end;  
  20.       
  21.     public PrintTask() {  
  22.         // TODO Auto-generated constructor stub  
  23.     }  
  24.       
  25.       
  26.       
  27.     //打印从start到end之间的任务  
  28.     public PrintTask(int start, int end) {  
  29.         super();  
  30.         this.start = start;  
  31.         this.end = end;  
  32.     }  
  33.   
  34.   
  35.   
  36.   
  37.     @Override  
  38.     protected void compute() {  
  39.           
  40.         if(end-start<threshold){  
  41.             for(int i=start;i<end;i++){  
  42.                   
  43.                 System.out.println(Thread.currentThread().getName()+"i的值:"+i);  
  44.             }  
  45.         }else{  
  46.             //当end与start之间的差大于threshold,及打印的数超过50个时,  
  47.             //将大任务分解成2个小任务  
  48.             int middle=(start+end)/2;  
  49.             PrintTask left=new PrintTask(start, middle);  
  50.             PrintTask  right=new PrintTask(middle, end);  
  51.             //并行执行两个小任务  
  52.             left.fork();  
  53.             right.fork();  
  54.               
  55.         }  
  56.           
  57.           
  58.     }  
  59.       
  60.       
  61.   
  62. }  

Java代码  收藏代码
  1. package com.demo;  
  2.   
  3. import java.util.concurrent.ForkJoinPool;  
  4. import java.util.concurrent.ForkJoinTask;  
  5. import java.util.concurrent.TimeUnit;  
  6. /** 
  7.  * 测试打印 
  8.  *  
  9.  * */  
  10. public class Test {  
  11.   
  12.       
  13.     public static void main(String[] args)throws Exception {  
  14.         ForkJoinPool pool=new ForkJoinPool();  
  15.         //提交可分解的任务  
  16.         pool.submit(new PrintTask(0,101));  
  17.           
  18.         //阻塞等待所有任务完成   
  19.         pool.awaitTermination(2, TimeUnit.SECONDS);  
  20.         pool.shutdown();//关闭线程池  
  21.           
  22.     }  
  23. }  

有返回值的demo 
Java代码  收藏代码
  1. package com.demo;  
  2.   
  3. import java.util.concurrent.RecursiveTask;  
  4. /*** 
  5.  * 有返回值 
  6.  *  
  7.  * */  
  8. public class CalTask  extends RecursiveTask<Integer>{  
  9.   
  10.       
  11.       
  12.     //将每个小任务,最多只能累加20个数  
  13.     private static final int threshold=20;  
  14.     private int arr[];  
  15.     private int start;//开始  
  16.     private int end;//  
  17.     //累加从start到end之间的数  
  18.       
  19.     public CalTask() {  
  20.         // TODO Auto-generated constructor stub  
  21.     }  
  22.       
  23.       
  24.     //累加从start到end的数组元素  
  25.     public CalTask(int[] arr, int start, int end) {  
  26.         super();  
  27.         this.arr = arr;  
  28.         this.start = start;  
  29.         this.end = end;  
  30.     }  
  31.   
  32.   
  33.   
  34.     @Override  
  35.     protected Integer compute() {  
  36.         int sum=0;  
  37.         //当end与start之间的差小于threshold,开始进行累加  
  38.         if(end-start<threshold){  
  39.             for(int i=start;i<end;i++){  
  40.                 sum+=arr[i];  
  41.             }  
  42.             return sum;  
  43.               
  44.         }else{  
  45.               
  46.             //当end与start之间的差大于threshold,要计算的数超过20个时,  
  47.             //将大任务分解成两个小任务  
  48.               
  49.             int middle=(start+end)/2;  
  50.             CalTask left=new CalTask(arr, start, middle);  
  51.             CalTask right=new CalTask(arr, middle, end);  
  52.             //并行执行2个小任务  
  53.             left.fork();  
  54.             right.fork();  
  55.             //把2个小任务,累加的结果合并起来  
  56.             return left.join()+right.join();  
  57.         }  
  58.            
  59.            
  60.     }  
  61.       
  62.   
  63. }  


Java代码  收藏代码
  1. package com.demo;  
  2.   
  3. import java.util.Random;  
  4. import java.util.concurrent.ForkJoinPool;  
  5. import java.util.concurrent.Future;  
  6.   
  7. public class Sum {  
  8.       
  9.       
  10.     public static void main(String[] args)throws Exception {  
  11.           
  12.         int []arr=new int[1100];  
  13.         Random rand=new Random();  
  14.         int total=0;  
  15.         //初始化100个数字  
  16.         for(int i=0;i<arr.length;i++){  
  17.             int tmp=rand.nextInt(20);  
  18.             //对元素赋值,并将数组元素的值添加到total总和中  
  19.             total+=(arr[i]=tmp);  
  20.               
  21.               
  22.         }  
  23.         System.out.println("正确的total:"+total);  
  24.         ForkJoinPool pool=new ForkJoinPool();  
  25.         //提交可分解的CalTask任务  
  26.         Future<Integer> future=pool.submit(new CalTask(arr, 0, arr.length));  
  27.         System.out.println(future.get());  
  28.         //关闭线程池  
  29.           
  30.         pool.shutdown();  
  31.     }  
  32.   
  33. }  
  34. 转载:http://qindongliang.iteye.com/blog/1912839
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值