笔记目录
1.Executors类和ExecutorService接口
1.1 Executors工具类的使用
Executors类似于Collections作用域集合领域一样,它是线程池的工具类,可以通过静态方法构造出不同特性的线程池让我们快速使用。常见的Executors创建线程池有几种:
- `ExecutorService executorService = Executors._newFixedThreadPool_(10);`这是创建定长的线程池,核心线程和最大线程数一致,且是一个无界队列(理论上)LinkedBlockingQueue实现。
- `ExecutorService executorService = Executors._newCachedThreadPool_();`这是创建可缓存线程池,他核心线程为0,最大线程是Integer.MAX_VALUE,队列使用的`SynchronousQueue`,所以这种线程池在面对多任务的时候会有许多线程创建。
- `ExecutorService executorService = Executors._newSingleThreadExecutor_();`这是创建一个单线程的线程池,他的核心和最大线程数量只有1个,使用无界队列LinkedBlockingQueue。
- `ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();`这是创建一个周期任务线程池,他的核心线程数只有1个,基于ScheduledExecutorService接口的实现。
1.2 ExecutorService接口
ExecutorService接口继承自Executor接口,Executor接口至定义了一个execute(Runnable r)抽象方法,ExecutorService是对Executor的补充,它定义了线程池的一系列同样方法:
- void shutdown():线程有序关闭,不会接受新的任务,等待现有任务执行结束再关闭。
- List<Runnable> shutdownNow():强制关闭线程池,返回`正在等待中的任务列表`。
- boolean isShutdown():判断线程池是否关闭。
- Future submit(Callable):提交Callable任务。
- Future submit(Runnable r, T result):支持提交Runnable类型的有返回值的任务。
- List<Future> invokeAll(Collection<? extends Callable> tasks):提交一组Callable任务。
1.3 自定义线程池ThreadPoolExecutor
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5,
10,
60L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(50),
new ThreadFactory(){
@Override
public Thread newThread(Runnable r) {return null;}},
new RejectedExecutionHandler(){
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {}}
);
threadPool.execute(() -> {xxx});
Future<?> result = threadPool.submit(() -> {xxx});
2.线程池参数含义
- int corePoolSize:核心线程的数量,在未设置核心线程的超时时间,他们是常驻的。
- int maximumPoolSize:最大线程的数量。
- long keepAliveTime:当线程数大于核心线程时,多余的空闲线程的最大存活时间。
- TimeUnit unit:存活时间的单位。
- BlockingQueue<Runnable> workQueue:任务等待队列。
- ThreadFactory threadFactory:线程工厂,需要具体实现。
- RejectedExecutionHandler handler:当工作队列满时,后续的任务提交的拒绝策略,需要具体实现。常见的实现有:拒绝任务并抛异常、拒绝任务不抛异常、交由调用者线程执行、丢弃最旧的任务。也可以自己实现。
3.线程池的工作流程
线程池ThreadPoolExecutor的工作流程:
1. 最开始线程池里没有工作线程,当有一个任务提交进来后,线程池就会为其addWord创建一个线程来执行这个任务。
1. 当任务继续提交,如果总的线程数已经达到了核心线程数的阈值,那么新的任务就会进入阻塞队列中去。不过这里的任务不会立即入队,而是会再次check检查线程池的状态。
1. 如果没有任务继续提交或者队列是无界队列,那么线程池的线程数量不会继续增加,核心工作线程不断消费队列的任务。
1. 如果仍然有任务提交,一旦任务阻塞队列满了,那么线程池就会创建maxThreads - coreThreads数量线程来消费队列中的任务。
1. 这些非核心线程的线程在执行完任务后,没有任务可执行后经过一段时间就会被回收。
1. 如果队列已满的情况,且线程池线程的数量已经超过最大的阈值,新的任务就会触发拒绝策略。
4.线程池原理窥探
4.1 线程池的状态如何记录
线程池的运行状态是通过他的成员变量COUNT_BITS
,来记录。他是表示int的位数。count_bits = 32-3 = 29。线程池用int的高3位来表示线程池的运行状态,后29位表示线程数量。
线程池状态 | 3位二进制的状态值 | 说明 |
---|---|---|
running | 111 | 能够接收任务,能够阻塞任务 |
shutdown(调用shutdown方法) | 000 | 不接受新任务,执行正在执行的任务 |
stop(调用shutDownNow方法) | 001 | 不接受新任务,打断正在执行的任务,丢弃队列中的任务。 |
tidying | 010 | 任务全部执行完毕,活动线程回收 |
terminated | 011 | 线程池终结状态 |