线程6-线程池
1、几个概念:
(1)线程池 ThreadPoolExecutor:存放线程的池子( --!)
(2)线程 Thread:用于执行实现<Runnable>接口的任务
(3)任务缓存队列:用于存放Thread要执行的任务
2、几个变量和方法的解释
(1)ThreadPoolExecutor的构造方法参数
corePoolSize:核心池的大小,在创建了线程池后,默认情况下,线程数为0。当有任务来了之后,就创建一个线程
去执行任务,当线程池中的线程数达到corePoolSize之后,就会尝试把新到达的任务放到缓存队列中
maximumPoolSize:线程池中最大线程数
keepAliveTime:线程池中的某个线程在多久没有执行任务时,线程会终止
unit:参数keepAliveTime的时间单位,有7种取值,参见TimeUnit类
workQueue:一个阻塞队列,用来存储等待执行的**任务**(非线程),阻塞队列有以下几种选择
一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
(2)execute()方法,可向线程池提交一个任务,交由线程池去执行
(3)submit()方法,也是向线程池提交一个任务,它能够返回任务结果,看源码可知,
其实submit()也是调用了execute,只不过它使用了RunnableFutureo类来获取线程执行结果
(4)shutdown(),等所有任务执行完毕后,关闭线程池
(5)shutdownNow(),马上关闭线程池,不管任务是否完成
(6)拒绝策略,通常有以下4种策略
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
(7)任务缓存队列及排队策略
任务缓存策略,即workQueue,用来等待任务执行的任务
workQueue通常有以下3种类型
1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE(0x7fffffff);
3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
(8)在ThreadPoolExecutor类中定义了一个volate变量,用来指示线程池状态,线程池有4种状态
1)static final int RUNNING = 0;
2)static final int SHUTDOWN = 1;
3)static final int STOP = 2;
4)static final int TERMINATED = 3;
创建后,线程池处于RUNNING状态
shutdown()后,线程处于SHUTDOWN状态,此时它只等待所有线程执行完任务,不接受新任务
shotdownNow()后,线程处于STOP状态,它不接受任务,尝试终止正在执行的任务
线程池处于STOP状态后,并且所有工作线程已销毁,任务缓存队列已清空或执行结束后,线程池被置为TERMINATED(结束)状态
3、线程池的工作流程
创建线程池(ThreadPoolExecutor)时,会指定核心池(corePoolSize)和线程池的最大线程容量(maximumPoolSize)
(1)创建线程池,线程池中线程为0,任务缓存队列中的任务为0
(2)ThreadPoolExecutor对象使用execute方法,向线程池提交一个任务
(3)线程池拿到任务,进行判断
如果当前线程池中的线程数,=<corePoolSize,创建一个新线程去执行任务
如果当前线程池中的线程数,大于corePoolSize并且小于maximumPoolSize,
则线程池会尝试把任务放到任务缓存队列,
如果放入缓存队列失败(一般来说是任务缓存队列已满),线程池尝试创建线程来执行任务
放入缓存队列成功,任务就等待空闲线程来取出执行
如果当前线程池中的线程数,等于maximunPoolSize,
则线程池会尝试把任务放到任务缓存队列,
如果放入缓存队列成功,任务就等待空闲线程来取出执行
如果放入缓存队列失败(一般来说是任务缓存队列已满),则会采取拒绝策略进行处理
4、线程池例子
package com.线程池; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class Test { public void testThread() throws InterruptedException { /**线程池构造方法中 * public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) (1)corePoolSize:核心池的大小,在创建了线程池后,默认情况下,线程数为0当有任务来了之后,就创建一个线程 去执行任务,当线程池中的线程数达到corePoolSize之后,就会把新到达的任务放到缓存队列中 (2)maximumPoolSize:线程中最大线程数 (3)keepAliveTime:线程池中的某个线程在多久没有执行任务时,会终止 (4)unit:参数keepAliveTime的时间单位,有7种取值,参见TimeUnit类 (5)workQueue:一个阻塞队列,用来存储等待执行的**任务**(非线程),阻塞队列有以下几种选择: ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue; ArrayBlockingQueue和PriorityBlockingQueue使用较少, 一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。 */ ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(6));//参数6是阻塞队列的容量 //执行任务 for(int i = 0 ; i < 15 ; i ++){ MyMask mask = new MyMask(i); /** * ThreadPoolExecutor的四个方法 * (1)execute()方法,可向线程池提交一个任务,交由线程池去执行 * (2)submit()方法,也是向线程池提交一个任务,它能够返回任务结果,看源码可知, * 其实submit()也是调用了execute,只不过它使用了RunnableFutureo类来获取线程执行结果 * (3)shutdown(),等所有任务执行完毕后,关闭线程池 * (4)shutdownNow(),马上关闭线程池,不管任务是否完成 */ executor.execute(mask); System.out.println("线程池中的线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数:"+executor.getQueue().size() +",已执行完的任务数:"+executor.getCompletedTaskCount()); //Thread.currentThread(); //Thread.sleep(2000); } executor.shutdown(); } public static void main(String[] args) { Test test = new Test(); try { test.testThread(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class MyMask implements Runnable{ private Integer intNum; public MyMask(int num){ this.intNum = num; } @Override public void run() { System.out.println("正在执行task "+intNum); Thread.currentThread(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("task "+intNum+"执行完成"); } }
参考:http://www.cnblogs.com/dolphin0520/p/3932921.html 原文写的很棒,讲的非常清晰,这篇博客是我按照自己的理解方式,重新整理了一下。