Java7之线程池ForkJoinPool

许多情况下,在一个程序中使用多线程是有益处的,可以大大提高程序的效率,多线程主要有以下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
  41.             for(int i=start;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{  
  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
  39.             for(int i=start;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
  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 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

你可能感兴趣的:(我的饭碗,java线程)