一般单线程运行结束后,线程被销毁。如果线程过多的话,频繁的创建和销毁线程会大大浪费时间和效率。线程池可以让线程运行结束后不立即销毁,而是被重复利用。
线程池使用
线程池最上层的接口是Executor。这个接口定义了核心方法run(Runnable command)。这个方法最后被ThreadPoolExecutor实现。
构造方法的参数及其含义
- corePoolSize:核心线程池的大小,如果核心线程池有空闲位置,这是新的任务就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
- maximunPoolSize:线程池能创建最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
- keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
- unit:时间单位,和keepAliveTime配合使用。
- workQueue:缓存队列,用来存放等待被执行的任务。
- threadFactory:线程工厂,用来创建线程,一般有三种选择策略。
- ArrayBlockingQueue;
- LinkedBlockingQueue;
- SynchronousQueue;
- handler:拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略,四种策略为
- ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。默认的拒绝方式。
- ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
- ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
线程池状态
RUNNING、SHURDOWN、STOP、TERMINATED
线程池创建后处于RUNNING状态。
调用shutdown后处于SHUTDOWN状态,线程池不能接受新的任务,会等待缓冲队列的任务完成。
调用shutdownNow后处于STOP状态,线程池不能接受新的任务,并尝试终止正在执行的任务。
当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。
创建线程池
一般不直接使用ThreadPoolExecutor方法,而是通过Executors提供给的几个静态方法来创建线程池。实际内部实现是指定好参数的ThreadPoolExecutor。
1 | Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE |
- newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;
- newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;
- newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。
源码解析
Executor
1 | public interface Executor { |
ThreadPoolExecutor构造方法
1 | public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, |
线程池图:
创建线程池
1 | public static ExecutorService newCachedThreadPool() { |
excute方法
注释中处理步骤解释的很详细
1 | public void execute(Runnable command) { |
运用到的设计模式
工厂模式(创建)
策略模式(拒绝策略)