线程池的5种状态

状态分类
RUNNING

线程池处在 RUNNING 状态时,能够接收新任务,以及对已添加的任务进行处理。该状态是线程池的初始状态,线程池一旦被创建,就处于 RUNNING 状态

SHUTDOWN

线程池处于 SHUTDOWN 状态时,不接收新任务,但能处理等待队列中的任务。线程池在 RUNNING 状态下,调用 shutdown() 方法,会变成 SHUTDOWN 状态。

STOP

线程池处于 STOP 状态时,不接收新任务,不再处理等待队列中的任务,并且会中断正在处理的任务线程池在 RUNNING 状态下,调用 shutdownNow() 方法,变为 STOP 状态

TIDYING

所有的任务都销毁了,工作线程数量为0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()线程池在 SHUTDOWN 状态时,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN 状态变为 TIDYING 状态;线程池在 STOP 状态时,线程池中执行的任务为空时,就会由 STOP 状态变为 TIDYING 。

TERMINATED

terminated() 方法执行之后,线程池彻底终止,就变成 TERMINATED 状态。

b2d68600f0dbea2606b1077ff12a04d3.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

public XSSFWorkbook createExcel(List<DataHistory> list, ArrayList<String> titles) throws IOException {
// 创建工作薄对象
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建sheet页
XSSFSheet sheet = workbook.createSheet();
// 自动换行
XSSFCellStyle style = workbook.createCellStyle();
style.setWrapText(true);
// 创建sheet页的行 表头
XSSFRow row = sheet.createRow(0);
int columnIndex = 0;
for (String value : titles) {
// 创建单元格
XSSFCell cell = row.createCell(columnIndex++);
cell.setCellValue(value);
}
//写入每行的数据
if (list != null) {
int rowNum = 1; //从第一行开始
for (DataHistory dataHistory : list) {
columnIndex = 0; //列数重置为0
XSSFRow newRow = sheet.createRow(rowNum++);
//创建线程池
ExecutorService es = Executors.newCachedThreadPool();

CountDownLatch doneSignal = new CountDownLatch(5);
try {
for (String value : titles) {
XSSFCell cell = newRow.createCell(columnIndex++);
es.submit(
new Runnable() {
@Override
public void run() {
cell.setCellValue(getValues(value, dataHistory));
doneSignal.countDown();
}
}
);

}
//使用CountDownLatch的await方法,等待所有线程完成sheet操作
doneSignal.await();
es.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return workbook;
}

CountDownLatch

是一个同步工具类,用来协调多个线程之间的同步,能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务

线程池实现方式

Executor

Executor 接口是线程池框架中最基础的部分,定义了一个 void execute(Runnable command) 方法,代表提交一个任务,由线程池来执行这个任务。

ExecutorService

Executor 下有一个重要子接口 ExecutorService,其中定义了一些可以操作线程池的方法:

public interface ExecutorService extends Executor {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 关闭线程池,已经提交的任务继续执行,不再接受新的任务
void shutdown();

// 尝试停止正在执行的任务,返回等待执行的任务列表。因为停止正在执行的线程使用 Thread.interrupt() 方法, 所以不保证能够完全停止
List<Runnable> shutdownNow();

// 当前线程池是否已经关闭
boolean isShutdown();

// 如果关闭后,所有任务都已经完成,则返回true
// 并且只有先调用 shutdown 或 shutdownNow 才会返回 true
boolean isTerminated();

// 等待请求关闭线程池后,所有的任务完成或者等待超时
// 如果所有的任务都已经完成了,则返回 true,超时的话返回 false
boolean awaitTermination(long timeout, TimeUnit unit);

// 提交一个 Callable 任务,并返回一个表示任务的挂起结果的 Future,之后可以通过 Future 的 get() 方法来获取任务成功完成后返回的结果
<T> Future submit(Callable<T> task);

// 提交一个 Runnable 任务,因为 Runable 的 run() 方法没有返回值,第二个参数会放到 Future 中作为返回值
<T> Future submit(Runnalbe task, T result);

// 提交一个 Runable 任务,因为没有指定返回值,所以之后在 Future 中获取的返回值为 null
Future<?> submit(Runnable task);

// 执行所有任务,返回 Future 类型的集合
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks);

// 执行所有任务,但设置了超时时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);

// 执行所有的任务,只要其中一个执行结束,就可以返回那个任务的结果
<T> invokeAny(Collection<? extends Callable<T>> tasks);

// 同上一个方法,设置了超时时间
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);
ThreadPoolExecutor

JDK 中线程池的默认实现,实现了线程池中的基本方法,可以直接使用,或者基本它扩展,来实现我们需要的功能,下面这个是 ThreadPoolExecutor 的核心构造函数,其他的构造函数最终都会走到该构造方法

1
2
3
4
5
6
7
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectExecutionHandler handler
参数说明
  • corePoolSize 是线程池中的核心线程数maxinumPoolSize 是线程池中允许的最大线程数,当当前正在运行的线程数小于 corePoolSize 值,新提交任务时,会创建一个新的线程来执行,即使有空闲的线程;当当前正在运行的线程数大于 corePoolSize 值,且小于maximumPoolSize 值,新任务会提交到等待队列中,直到等待队列满了,才会创建新的线程执行任务。
  • keepAliveTime线程允许的最大空闲时间。且默认情况下,只会在超时后,销毁非核心线程。也可以通过调用 allowCoreThreadTimeOut(true) 方法,来将这种策略应用于核心线程
  • unit,keepAliveTime 的时间单位
  • workQueue 是用来保存等待被执行任务的阻塞队列,通常和线程池的大小对应调整。
  • threadFactory创建线程的工厂类,用来创建新线程
  • handler线程池的拒绝策略,当线程池处于关闭状态,或者阻塞队列满了,而且线程数量已经达到了 maximumPoolSize,再提交任务时,就会执行当前指定的策略