JAVA线程池
java.uitl.concurrent.ThreadPoolExecutor类是使用线程池时主要用到的类。在ThreadPoolExecutor类中提供了四个构造方法:
public class ThreadPoolExecutor extends AbstractExecutorService { ..... public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); ... }
下面解释下一下构造器中各个参数的含义:
- corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
- maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
- keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
- unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小时 TimeUnit.MINUTES; //分钟 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //纳秒
- workQueue:任务缓存队列。当核心线程全部占用后,新来的线程会放到任务缓存队列中等待开启新的线程或者等待核心线程空闲后来执行。该参数会影响等待线程的排队策略。workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型: 1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
- handler:表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
线程池类ThreadPoolExecutor的使用
1.定义ThreadPoolExecutor 对象
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(15));
其中corePoolSize=5代表线程中有5个核心线程来执行线程任务,当加入的线程超出5个后,放到任务缓存队列中等待执行,等核心线程执行完后从任务缓存队列中取出来执行,如果还有新的线程加进来,会开辟新的线程执行进入的线程,但是最多新开辟10个线程,如果还有线程进入线程池,这时候会抛出异常。
2.执行线程
首先创建线程,然后调用execute函数使线程加载到线程池中。
3.线程池的关闭
当线程池执行完毕或者需要关闭时,ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
- shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
- shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
4.线程池容量的动态调整
ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),
- setCorePoolSize:设置核心池大小
- setMaximumPoolSize:设置线程池最大能创建的线程数目大小
当上述参数从小变大时,ThreadPoolExecutor进行线程赋值,还可能立即创建新的线程来执行任务。
下面通过具体的例子来说明线程池的使用:
线程类:
1 class RunThread implements Runnable{ 2 3 int Counter = 0; 4 @Override 5 public synchronized void run() { 6 7 try { 8 Thread.sleep(500); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 System.out.println(Thread.currentThread().getName()+"count:"+Counter++); 13 } 14 15 }
执行函数:
1 public static void main(String[] args) { 2 3 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, 4 new ArrayBlockingQueue<Runnable>(10)); 5 6 for (int i = 0; i < 15; i++) { 7 RunThread runThread = new RunThread(); 8 System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ 9 executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount()); 10 try { 11 executor.execute(runThread); 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 16 } 17 executor.shutdown(); 18 }
运行结果:
线程池中线程数目:0,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:6,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:7,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:8,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:9,已执行玩别的任务数目:0 pool-1-thread-2count:0 pool-1-thread-4count:0 pool-1-thread-1count:0 pool-1-thread-3count:0 pool-1-thread-5count:0 pool-1-thread-4count:0 pool-1-thread-2count:0 pool-1-thread-1count:0 pool-1-thread-3count:0 pool-1-thread-5count:0 pool-1-thread-2count:0 pool-1-thread-4count:0 pool-1-thread-1count:0 pool-1-thread-5count:0 pool-1-thread-3count:0
修改参数:
new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
输出结果:
线程池中线程数目:0,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 pool-1-thread-4count:0 pool-1-thread-2count:0 pool-1-thread-5count:0 pool-1-thread-3count:0 pool-1-thread-1count:0 pool-1-thread-10count:0 pool-1-thread-9count:0 pool-1-thread-8count:0 pool-1-thread-7count:0 pool-1-thread-6count:0 pool-1-thread-4count:0 pool-1-thread-3count:0 pool-1-thread-5count:0 pool-1-thread-2count:0 pool-1-thread-1count:0
修改参数:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 8, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
输出结果:
线程池中线程数目:0,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 java.util.concurrent.RejectedExecutionException: Task com.uestc.xst.RunThread@1884174 rejected from java.util.concurrent.ThreadPoolExecutor@814013[Running, pool size = 8, active threads = 8, queued tasks = 5, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source) at com.uestc.xst.Main.main(Main.java:73) java.util.concurrent.RejectedExecutionException: Task com.uestc.xst.RunThread@192c8d9 rejected from java.util.concurrent.ThreadPoolExecutor@814013[Running, pool size = 8, active threads = 8, queued tasks = 5, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source) at com.uestc.xst.Main.main(Main.java:73) 线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0 pool-1-thread-3count:0 pool-1-thread-1count:0 pool-1-thread-2count:0 pool-1-thread-4count:0 pool-1-thread-5count:0 pool-1-thread-7count:0 pool-1-thread-6count:0 pool-1-thread-8count:0 pool-1-thread-3count:0 pool-1-thread-2count:0 pool-1-thread-5count:0 pool-1-thread-4count:0 pool-1-thread-1count:0
继续修改参数:
ThreadPoolExecutor executor = new ThreadPoolExecutor(15, 25, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
输出结果:
线程池中线程数目:0,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:6,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:7,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:8,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:9,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:11,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:12,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:13,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 线程池中线程数目:14,队列中等待执行的任务数目:0,已执行玩别的任务数目:0 pool-1-thread-1count:0 pool-1-thread-5count:0 pool-1-thread-3count:0 pool-1-thread-2count:0 pool-1-thread-4count:0 pool-1-thread-9count:0 pool-1-thread-7count:0 pool-1-thread-10count:0 pool-1-thread-8count:0 pool-1-thread-6count:0 pool-1-thread-11count:0 pool-1-thread-13count:0 pool-1-thread-14count:0 pool-1-thread-15count:0 pool-1-thread-12count:0
结果分析:
当线程池中线程大小达到核心线程上限时,如果还有线程开启,会优先放到任务缓存队列中,如果队列满了,则在MaximunPoolSize未满时,则开辟新的线程,如果MaximunPoolSize已满,则会抛出异常。
参考文献:http://www.cnblogs.com/dolphin0520/p/3932921.html