ThreadPoolExecutor使用

转自:http://blog.csdn.net/geminiroy/article/details/6543916

从JDK1.5开始引入了线程池,类为 java.util.concurrent.ThreadPoolExecutor
常用的构造方法:

  1. public ThreadPoolExecutor(int corePoolSize,  
  2.                               int maximumPoolSize,  
  3.                               long keepAliveTime,  
  4.                               TimeUnit unit,  
  5.                               BlockingQueue<Runnable> workQueue,  
  6.                               RejectedExecutionHandler handler)  

 

各个参数的意义:

corePoolSize                       保留的线程池大小,只要本线程池存在,这就是最小的线程数

maximumPoolSize               线程池的最大大小

keepAliveTime                     空闲线程被清理的超时时间

unit                                     枚举上面的keepAliveTime所用单位,用法如:TimeUnit.SECONDS

workQueue                         一个存放任务的阻塞队列,常用实现如ArrayBlockingQueue和LinkedBlockingQueue

handler                               线程池无法处理后续线程时,执行的处理策略

 

线程池的工作流程如下:

1. 线程池刚开始工作时,里面没有一个线程,队列是通过参数传入的;不过,就算队列里有任务,线程池也不会立即执行他们

2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a. 如果正在执行的线程数小于corePoolSize,那么马上创建线程运行这个任务;

b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;

c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

3.当一个线程完成任务时,它会从队列中取下一个任务来执行。

4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

这样的过程说明,并不是先加入任务就一定会先执行——假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4~13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。

 

了解了工作流程,看看几个参数的意义和用法:

workQueue:所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互

排队有三种通用策略:

     直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集合时出现锁定。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

     无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙的情况下将新任务加入队列。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

     有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

handler: 线程池处理满仓状态的策略,预定义四种:

     ThreadPoolExecutor.AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionException

     ThreadPoolExecutor.DiscardPolicy:不能执行的任务将被删除。

     ThreadPoolExecutor.CallerRunsPolicy:线程调用运行该任务的execute本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

     ThreadPoolExecutor.DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。

 

下面是一个简单的使用ThreadPoolExecutor的例子:

  1. package gss.study.thread;  
  2.   
  3. import java.util.concurrent.ArrayBlockingQueue;  
  4. import java.util.concurrent.ThreadPoolExecutor;  
  5. import java.util.concurrent.TimeUnit;  
  6.   
  7. import gss.util.S;  
  8.   
  9. /** 
  10.  * 这个例子也可以体会ThreadLocal的作用和用法 
  11.  * @author gss 
  12.  * 
  13.  */  
  14. public class Admin implements Runnable{  
  15.     Worker worker = null;  
  16.     int no ;  
  17.     public Admin(Worker worker,int no) {  
  18.         this.worker = worker;  
  19.         this.no=no;  
  20.     }  
  21.   
  22.     @Override  
  23.     public void run() {  
  24.         this.worker.setNo(no);  
  25.         this.worker.work();  
  26.     }  
  27.       
  28.     public static void main(String[] args) {  
  29.           
  30.         //如果是以下设置,则输出为   
  31.         /* 
  32.         pool-1-thread-1 普通参数 4 
  33.         pool-1-thread-1 ThreadLocal 0 
  34.         pool-1-thread-2 普通参数 1 
  35.         pool-1-thread-2 ThreadLocal 1 
  36.         pool-1-thread-1 普通参数 3 
  37.         pool-1-thread-1 ThreadLocal 3 
  38.         pool-1-thread-4 普通参数 4 
  39.         pool-1-thread-4 ThreadLocal 4 
  40.         pool-1-thread-5 普通参数 5 
  41.         pool-1-thread-5 ThreadLocal 5 
  42.         pool-1-thread-3 普通参数 2 
  43.         pool-1-thread-3 ThreadLocal 2 
  44.          */  
  45.         //可以体会这些参数的作用,最大pool为5,队列为1,销毁时间是1s,策略是discard,则在满六个之后后面的被丢弃   
  46. //      ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS,    
  47. //              new ArrayBlockingQueue(1), new ThreadPoolExecutor.DiscardPolicy());   
  48.           
  49.           
  50.         //换了策略,输出为:   
  51.         /*   
  52.          *  pool-1-thread-5 普通参数 5 
  53.             pool-1-thread-5 ThreadLocal 5 
  54.             pool-1-thread-1 普通参数 5 
  55.             pool-1-thread-1 ThreadLocal 0 
  56.             pool-1-thread-3 普通参数 5 
  57.             pool-1-thread-3 ThreadLocal 2 
  58.             pool-1-thread-2 普通参数 5 
  59.             pool-1-thread-2 ThreadLocal 1 
  60.             pool-1-thread-4 普通参数 5 
  61.             pool-1-thread-4 ThreadLocal 4 
  62.             main 普通参数 5 
  63.             main ThreadLocal 6 
  64.             pool-1-thread-5 普通参数 7 
  65.             pool-1-thread-5 ThreadLocal 3 
  66.             pool-1-thread-1 普通参数 7 
  67.             pool-1-thread-1 ThreadLocal 7 
  68.             main 普通参数 7 
  69.             main ThreadLocal 8 
  70.             pool-1-thread-6 普通参数 9 
  71.             pool-1-thread-6 ThreadLocal 9 
  72.          */  
  73.         //调用了主线程来完成工作,这个选项可以较好的完成   
  74. //      ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MICROSECONDS,    
  75. //              new ArrayBlockingQueue(1), new ThreadPoolExecutor.CallerRunsPolicy());   
  76.           
  77.         //输出为   
  78.         /* 
  79.          * Exception in thread "main" java.util.concurrent.RejectedExecutionException 
  80.                 at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1768) 
  81.                 at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:767) 
  82.                 at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:658) 
  83.                 at gss.study.thread.Root.main(Root.java:78) 
  84.             pool-1-thread-3 普通参数 4 
  85.             pool-1-thread-1 普通参数 4 
  86.             pool-1-thread-1 ThreadLocal 0 
  87.             pool-1-thread-4 普通参数 4 
  88.             pool-1-thread-4 ThreadLocal 4 
  89.             pool-1-thread-2 普通参数 4 
  90.             pool-1-thread-2 ThreadLocal 1 
  91.             pool-1-thread-5 普通参数 4 
  92.             pool-1-thread-5 ThreadLocal 5 
  93.             pool-1-thread-3 ThreadLocal 2 
  94.             pool-1-thread-1 普通参数 3 
  95.             pool-1-thread-1 ThreadLocal 3 
  96.          */  
  97.         //可以看到AbortPolicy的作用,抛出异常!   
  98. //      ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MICROSECONDS,    
  99. //              new ArrayBlockingQueue(1), new ThreadPoolExecutor.AbortPolicy());   
  100.           
  101.         //把队列设的足够大,则都能处理   
  102.         /* 
  103.          * pool-1-thread-3 普通参数 2 
  104.             pool-1-thread-3 ThreadLocal 2 
  105.             pool-1-thread-2 普通参数 2 
  106.             pool-1-thread-2 ThreadLocal 1 
  107.             pool-1-thread-1 普通参数 2 
  108.             pool-1-thread-1 ThreadLocal 0 
  109.             pool-1-thread-2 普通参数 5 
  110.             pool-1-thread-2 ThreadLocal 4 
  111.             pool-1-thread-1 普通参数 5 
  112.             pool-1-thread-1 ThreadLocal 5 
  113.             pool-1-thread-3 普通参数 5 
  114.             pool-1-thread-3 ThreadLocal 3 
  115.             pool-1-thread-2 普通参数 8 
  116.             pool-1-thread-2 ThreadLocal 6 
  117.             pool-1-thread-3 普通参数 9 
  118.             pool-1-thread-3 ThreadLocal 8 
  119.             pool-1-thread-1 普通参数 9 
  120.             pool-1-thread-1 ThreadLocal 7 
  121.             pool-1-thread-2 普通参数 9 
  122.             pool-1-thread-2 ThreadLocal 9 
  123.          */  
  124.         //所以线程池的效果,要根据特定的应用场景选择合适的设置   
  125.         ThreadPoolExecutor tpe = new ThreadPoolExecutor(351, TimeUnit.MICROSECONDS,   
  126.                 new ArrayBlockingQueue(100), new ThreadPoolExecutor.AbortPolicy());  
  127.           
  128.         Worker w = new Worker();  
  129.         for (int i=0;i<10;i++) {  
  130.             Admin m = new Admin(w,i);  
  131.             tpe.execute(m);  
  132.         }  
  133.           
  134.         tpe.shutdown();  
  135.     }  
  136. }  
  137.   
  138. class Worker {  
  139.     int no;  
  140.     ThreadLocal<Number> threadLocalNo = new ThreadLocal<Number>();  
  141.       
  142.       
  143.     public int getNo() {  
  144.         return no;  
  145.     }  
  146.     public void setNo(int no) {  
  147.         this.no = no;  
  148.         this.threadLocalNo.set(no);  
  149.     }  
  150.       
  151.     public void work() {  
  152.         try {  
  153.             Thread.currentThread().sleep(1000);  
  154.         } catch (InterruptedException e) {  
  155.             // TODO Auto-generated catch block   
  156.             e.printStackTrace();  
  157.         }  
  158.         S.echo(Thread.currentThread().getName()+" 普通参数 "+this.no);  
  159.         S.echo(Thread.currentThread().getName()+" ThreadLocal "+this.threadLocalNo.get());  
  160.     }  
  161. }  

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值