一、引入背景
1. 线程频繁的创建和销毁会消耗大量系统资源
2. 线程上线文切换会消耗大量系统资源
3. 线程数量太多,栈内存会溢出,因为每个线程都有自己的栈
4. 需要一种机制,可以线程复用,执行完一个任务后不销毁,继续执行其他任务
二、线程池定义
1. 接口关系
a. Executor接口,Excutor框架把任务的提交和执行进行解耦,只声明了一个方法execute()
b. ExecutorService: 真正的线程池接口,继承Executor接口
c. AbstractExecutorService:抽象类,实现了ExecutorService接口
d. ThreadPoolExecutor类: ExecutorService的默认实现,是线程池中最核心的类
e. 继承关系:ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor
2. ThreadPoolExecutor类构造方法的源码(重要!!!需要透彻理解)
public ThreadPoolExecutor( int corePoolSize, //线程池大小,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中; int maximumPoolSize, //线程池能创建的最大线程数,超出corePoolSize后的补救措施;超过maximumPoolSize进行拒绝 long keepAliveTime, //表示线程没有任务执行时(即在缓存队列中)最多保持多久时间会终止,当线程数大于corePoolSize才起作用,如果一个线程的空闲时间达到keepAliveTime,则会终止 TimeUnit unit, //参数keepAliveTime的时间单位 BlockingQueue<Runnable> workQueue, //一个阻塞队列,用来存储等待执行的任务,此时线程被阻塞 ThreadFactory threadFactory, //线程工厂,主要用来创建线程,可以对线程命名 RejectedExecutionHandler handler //表示拒绝处理任务时的策略,主要是丢弃任务 );
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
d. 线程池容量的动态调整 setCorePoolSize()和setMaximumPoolSize()
volatile int runState; //当前线程池的状态,volatile保证线程之间的可见性 static final int RUNNING = 0; //线程池创建后,初始时的状态 static final int SHUTDOWN = 1; //调用了shutdown()方法时的状态,此时线程池不接受新的任务 static final int STOP = 2; //调用了shutdownNow()方法时的状态,此时线程池不接受新的任务,并且回去尝试终止正在执行的任务 static final int TERMINATED = 3; // 线程池处于SHUTDOWN或者STOP状态后,所有的工作线程都已经销毁,任务缓存队列已经清空或执行结束,线程池会处于此状态
- prestartCoreThread():初始化一个核心线程;
- prestartAllCoreThreads():初始化所有核心线程
3. 任务缓存队列及排队策略, 如果超过了corePoolSize,会缓存线程到workQueue
4. 任务拒绝策略,如果超出了maxPoolSize,会拒绝任务并丢弃
四、线程池的使用:Executors的4个静态方法,底层实现都是ThreadPoolExecutor
newSingleThreadExecutor 创建只有一个线程的线程池
newFixedThreadPool 创建线程数量固定的线程池
newCachedThreadPool 创建可缓存的线程池,线程数量无限制
newScheduledThreadPool 创建周期性执行任务的线程池,线程数量限制
ExecutorService executorService = Executors.newFixedThreadPool(20);
Executor executor=Executors.newFixedThreadPool(20);
executorService.execute(() -> { // code });
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workQueueCount), new ThreadPoolExecutor.DiscardOldestPolicy() );
ExecutorService executorService = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workQueueCount), new ThreadPoolExecutor.DiscardOldestPolicy() );
threadPoolExecutor.execute(()->{ // code });