一.使用线程池的好处
1.提高系统性能和响应速度:线程池可以通过复用线程来减少线程的创建和销毁,从而减少了系统开销,提高了系统的性能和响应速度。
2.提高代码的可维护性:使用线程池可以将任务的执行与线程的创建和管理分离开来,使得代码更加清晰易懂,也更加容易维护。
3.提高代码的可复用性:线程池可以让不同的任务共享同一个线程池,从而提高代码的可复用性。
二.ThreadPoolExecutor线程池的参数解释
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
1.corePoolSize:核心线程池大小,即线程池中保留的线程数,即使它们处于空闲状态。如果新的任务提交给线程池时,核心线程池中的线程都在忙碌状态,那么新任务就会被添加到工作队列中等待执行。
2.maximumPoolSize:最大线程池大小,即线程池中最多可以创建的线程数。如果工作队列已满并且线程池中的线程数小于最大线程池大小,则会创建新的线程来执行任务。
3.keepAliveTime:空闲线程存活时间,即当一个线程处于空闲状态时,它最多可以存活多长时间。如果线程池中的线程数超过了核心线程池大小,空闲的线程将会被回收,直到线程池中的线程数等于核心线程池大小为止。
4.unit:keepAliveTime的时间单位。
5.workQueue:任务队列,用于存储等待执行的任务。当所有的核心线程都在执行任务时,新的任务会被添加到任务队列中等待执行。任务队列有多种实现方式,例如ArrayBlockingQueue、LinkedBlockingQueue等。
三.线程池的执行流程(execute方法)
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/**
* ctl中保存了两个信息,高3位保存的是线程池状态,低29位保存的是线程数量,
* ctl.get()方法用于检查线程池状态和线程数量
*/
int c = ctl.get();
/**
* 第一阶段:如果线程中的线程数小于核心线程数,那么就将线程添加到线程池中,
* 此时添加的线程类型是核心线程,占用corePoolSize的名额,添加成功则直接返回
* 如果核心线程池已满,则刷新线程池状态并执行第二阶段
*/
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
/**
* 第二阶段:如果核心线程数已满,则检查线程池运行状态,如果运行状态正常,
* 则执行workQueue.offer(command)方法,即添加线程到任务队列,成功则返回true,之后再次刷新线程池状态,
* 如果线程池不是running状态或者任务队列已满,则执行第三阶段
*/
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
/**
* 如果线程池不是running状态,则执行remove(command)方法,即从队列中移出任务,并执行拒绝策略
*/
if (! isRunning(recheck) && remove(command))
reject(command);
/**
* 如果线程池是running状态或者移出失败,则检测线程数量是否为0,
* 线程数量为0则添加线程到线程池中,此时添加的线程是非核心线程,且不执行任务
* 否则执行拒绝策略
*/
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
/**
* 第三阶段:如果任务队列已满,则添加线程到线程池中,这时添加的是非核心线程,
* 占用maximumPoolSize的名额,若添加失败,即maximumPoolSize已满,则执行拒绝策略
*/
else if (!addWorker(command, false))
reject(command);
}
1.当有任务需要执行时,首先判断当前线程池中的线程数是否小于核心线程数,如果是,则创建一个新的核心线程来执行任务。
2.如果当前线程池中的线程数已经达到核心线程数,则将任务放入任务队列中等待执行。
3.当任务队列已满时,如果当前线程池中的线程数还没有达到最大线程数,则创建新的非核心线程来执行任务。
4.如果当前线程池中的线程数已经达到最大线程数,则采取拒绝策略,例如抛出异常或者执行一些默认操作。