抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

JAVA线程池实现03-其余方法

shutdown安全停止任务

注意该方法不会马上停止线程池,会先将线程池置于shutdown状态然后发起中断请求,等待任务自己结束,线程内部要实现中断请求的响应处理,否则就不会终止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//安全的中断任务
public void shutdown() {
//获取重入锁
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
//检查权限
checkShutdownAccess();
//更改运行状态
advanceRunState(SHUTDOWN);
//中断任务
interruptIdleWorkers();
//模板方法,不继承实现则是一个空方法
onShutdown();
} finally {
//解锁
mainLock.unlock();
}
//尝试中断任务
tryTerminate();
}

检查权限 checkShutdownAccess

这主要的目的是为了在系统层面对线程池进行保护,防止其发生意外。比如中断系统进程等,获取了安全管理器之后接下来再对其进行权限检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 //检查线程池个任务权限
private void checkShutdownAccess() {
//获取安全管理器
SecurityManager security = System.getSecurityManager();
if (security != null) {
//检查任务权限
security.checkPermission(shutdownPerm);
//获取重入锁
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
//检查个任务的权限
for (ThreadPoolExecutor.Worker w : workers) {
security.checkAccess(w.thread);
}
} finally {
//解锁
mainLock.unlock();
}
}
}

更改运行状态 advanceRunState

更改线程池的状态

1
2
3
4
5
6
7
8
9
//设置运行状态
private void advanceRunState(int targetState) {
for (; ; ) {
int c = ctl.get();
//非运行状态 当前状态> targetState 或者 设置运行状态为 targetState状态成功
if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}

中断工作任务 interruptIdleWorkers

中断任务,但是只是发起中断请求,不会强制中断任务。

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
/**
* 中断任务
*/
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}

/**
* 中断任务
* @param onlyOne 是否只中断一次
*/
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();
}
}

尝试终止任务

尝试终止任务如果有正在运行的任务或者任务队列不为空且运行状态是SHUTDOWN就返回,不进行前置终止。

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
/**
* 尝试终止任务
*/
final void tryTerminate() {
//自旋
for (;;) {
//获取运行状态
int c = ctl.get();
/**
* isRunning 线程正在运行
* runStateAtLeast 线程池已经中断
* 或者 线程池停止并且任务队列不为空 返回
* 不进行强制终止
*
*/
//正在运行或者
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) {
return;
}
//当前工作线程不为0
if (workerCountOf(c) != 0) { // Eligible to terminate
//发起中断请求 只终止一次
interruptIdleWorkers(ONLY_ONE);
//返回
return;
}
//获取重入锁
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
//设置运行状态为真理状态
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
//空方法,用于终止线程后的自定义任务
terminated();
} finally {
//设置线程池为终止状态
ctl.set(ctlOf(TERMINATED, 0));
//通知所有线程
termination.signalAll();
}
return;
}
} finally {
//解锁
mainLock.unlock();
}
// else retry on failed CAS
}
}

shutdownNow马上终止线程

该方法是马上中断线程池,如果有未完成的任务先发起中断请求,然后将线程池中的任务删除,并将删除的数据放进一个临时的队列并且返回。

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
/**
* 马上终止线程
* @return 未完成的任务列表
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
//获取重入锁
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
//检查权限
checkShutdownAccess();
//设置状态为终止
advanceRunState(STOP);
//发起中断请求
interruptWorkers();
//将线程池任务队列清空,并返回未完成的任务
tasks = drainQueue();
} finally {
mainLock.unlock();
}
//尝试终止任务
tryTerminate();
return tasks;
}

drainQueue 清空队列

清理队列并且返回未完成任务的列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 清空队列,并返回清除的数据
* @return
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
//批量获取任务
q.drainTo(taskList);
//为防止还有剩余数据,做一次查询
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
//删除队列中的元素
if (q.remove(r)) {
//添加到队列
taskList.add(r);
}
}
}
return taskList;
}

shutdown与shutdownNow

到这里我们发现shutdown和 shutdownNow很像,但是有差别,shutdownNow就强制在调用后会清空任务列表,强制终止任务,但是shutdown不会,shutdown会等待任务完成然后才会进行终止。

isShutdown 线程池是否关闭

1
2
3
public boolean isShutdown() {
return ! isRunning(ctl.get());
}

isTerminating 线程池是否正在终止

1
2
3
4
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}

线程池是否终止

1
2
3
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}

评论