一、线程池有哪些类
1、可缓存线程池(NewCachedThreadPool)
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行
很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
2、 指定工作线程的线程池(NewFixedThreadPool)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
3、定时的线程池(newScheduledThreadPool)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
4、ThreadPoolExecutor
ThreadPoolExecutor与前几个线程池对比要更灵活
二、ThreadPoolExecutor解决什么问题
创建一个新的线程可以通过继承Thread类或者实现Runnable接口来实现,这两种方式创建的线程在运行结束后会被虚拟机销毁,进行垃圾回收,如果线程数量过多,频繁的创建和销毁线程会浪费资源,降低效率。而线程池的引入就很好解决了上述问题,线程池可以更好的创建、维护、管理线程的生命周期,做到复用,提高资源的使用效率,也避免了开发人员滥用new关键字创建线程的不规范行为。
1、ThreadPoolExecutor数据结构
ThreadPoolExecutor数据结构有 HashSet、BlockingQueue、Worker、AbstractQueuedSynchronizer构成。
2、ThreadPoolExecutor执行流程
1、任务添加 - 当线程池任务数小于核心线程数时,Worker 是继承Runnable的包装类,每一个任务都使用Worker包装起来,然后将包装对象存入HashSet中,直接唤醒其线程执行。
2、任务添加 - 当线程池任务数大于核心线程数时,执行方法直接放入BlockingQueue队列中,排队执行。如果队列满了执行队列拒绝策略。
3、线程回收- 当执行线程大于核心线程 或者 线程池关闭 或者 核心线程keepAliveTimeOut超时时候触发interruptIdleWorkers方法。 注意点interruptIdleWorkers回收原则是线程是否被发出中断请求,如果被发出中断请求执行回收。
三、ThreadPoolExecutor类重点方法列举
| 属性名称 | 解释 | 功能描述 |
|---|---|---|
| keepAliveTime | 线程空闲时间 | 一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut |
| allowCoreThreadTimeOut | 核心线程超时关闭 | 该属性用来控制是否允许核心线程超时退出。默认值为:false。如果线程池的大小已经达到了corePoolSize,不管有没有任务需要执行,线程池都会保证这些核心线程处于存活状态。该属性只是用来控制核心线程的 |
| poolSize | 线程池中当前线程的数量 | 线程池中当前线程的数量,当该值为0的时候,意味着没有任何线程 |
| corePoolSize | 核心线程数 | 线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。再考虑到keepAliveTime和allowCoreThreadTimeOut超时参数的影响,所以没有任务需要执行的时候,线程池的大小不一定是corePoolSize |
| maximumPoolSize | 线程池中允许的最大线程数 | 线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这里值得一提的是largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。为什么说是曾经呢?因为线程池创建之后,可以调用setMaximumPoolSize()改变运行的最大线程的数目 |
| queueCapacity | 任务队列容量(阻塞队列 | 当核心线程数达到最大时,新任务会放在队列中排队等待执行 |
| rejectedExecutionHandler | 任务拒绝处理器 | * 两种情况会拒绝处理任务: - 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务 - 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务 * 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常 * ThreadPoolExecutor类有几个内部实现类来处理这类情况: - AbortPolicy 丢弃任务,抛运行时异常 - CallerRunsPolicy 执行任务 - DiscardPolicy 忽视,什么都不会发生 - DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务 * 实现RejectedExecutionHandler接口,可自定义处理器 |
四、线程池源码解读
1、任务添加
1、当前线程数小于核心线程数,addWoker直接添加入Hashset中,直接唤醒addWorker线程执行。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//线程小于核心线程数,addWorker添加Hashset直接唤醒线程执行
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);
}
2、队列任务执行
线程池队列线程执行情况
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// 如果线程池停止执行线程回收
// 如果当前线程被中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
3、线程池线程回收
线程回收方法是线程安全的,如果线程被中断执行回收。
//线程池线程回收
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
本文详细介绍了Java线程池的几种类型,包括可缓存线程池、指定工作线程的线程池和定时线程池等,并深入解析了ThreadPoolExecutor的工作原理、执行流程及关键属性。

1405

被折叠的 条评论
为什么被折叠?



