说明
ThreadPoolExecutor 提供关闭线程池的方法,有以下3个:
shutdown()shutdownNow()awaitTermination()(不能实现关闭)
本文介绍这3个方法的区别
注意
在很多程序中,线程池与数据库连接池类似,即:一直开启并使用,不会关闭
结论
优雅的关闭,用 shutdown()
立刻关闭,并得到未执行任务列表,用 shutdownNow()
shutdown()
将线程池状态置为 SHUTDOWN
不会立即停止,而是做以下操作:
- 停止接收外部submit的任务
- 内部正在跑的任务和队列里等待的任务,会执行完
- 等到第二步完成后,才真正停止
例子
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown1 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
threadPoolExecutor.execute(new MyRun("2"));
// 关闭线程池,内部正在跑的任务和队列里等待的任务,执行完后才会真正关闭
threadPoolExecutor.shutdown();
// 关闭后,停止接收新提交的任务,会抛异常
try {
threadPoolExecutor.execute(new MyRun("3"));
}catch (Exception e){
System.out.println("拒绝接收任务:"+e.toString());
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name+"--结束");
}
}
}
shutdownNow()
将线程池状态置为 STOP。企图立即停止,事实上不一定
做以下操作:
- 跟
shutdown()一样,先停止接收外部提交的任务 - 忽略队列里等待的任务
- 尝试将正在跑的任务interrupt中断
- 返回未执行的任务列表
它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,但是,这种方法的作用有限,如果线程中没有 sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。
所以,ShutdownNow()并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。
但是 大多数时候是能立即退出的
例子:可以中断线程
通过 Thread.interrupt() 方法 中断线程池中的线程,前提是:线程执行 sleep() 、wait() 等方法
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown1 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
threadPoolExecutor.execute(new MyRun("2"));
// 关闭线程池,内部正在跑的任务和队列里等待的任务,执行完后才会真正关闭
threadPoolExecutor.shutdown();
// 关闭后,停止接收新提交的任务,会抛异常
try {
threadPoolExecutor.execute(new Shutdown1.MyRun("3"));
}catch (Exception e){
System.out.println("拒绝接收任务:"+e.toString());
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(name+"--结束");
}
}
}
例子:不能中断线程
由于线程中执行死循环,没有执行 sleep() 等操作,所以无法中断
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown3 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
1,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
/*
关闭线程池
通过 Thread.interrupt() 方法 中断线程池中的线程
由于线程执行 死循环,所以无法中断
*/
threadPoolExecutor.shutdownNow();
// 关闭后,停止接收新提交的任务,会抛异常
try {
threadPoolExecutor.execute(new MyRun("2"));
}catch (Exception e){
System.out.println("拒绝接收任务:"+e.toString());
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
for(int i=0;i<10000000;++i){
int res = i % 10000;
if(res == 0) {
System.out.println(name + "--运行中,循环次数:" +i);
}
}
}
}
}
shutdown()和shutdownNow()的区别
shutdownNow() 能立即停止线程池,正在跑的和正在等待的任务都停下了。这样做立即生效,但是风险也比较大;
shutdown() 只是关闭了提交通道,而内部线程还正常运行,运行完再停止线程池。
awaitTermination()
不是用来关闭线程池,而是等待 timeout 时间后,返回线程池 是否关闭
应用场景:一般在调用 shutdown() 方法后调用
方法声明
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException
形参:
timeout:时间unit:时间单位(当前是秒)
返回值: boolean 型,返回以下值:
- true:表示已经停止
- false:表示正在运行
执行后,当前线程阻塞(等待),直到满足下面条件之一后才会继续执行:
执行
shutdown()后,线程运行时间超过timeout时间,等待timeout时间返回 false执行
shutdown()后,线程运行时间少于timeout时间,等待timeout时间返回 true执行
shutdownNow()后,抛出InterruptedException异常,返回true
例子1
执行 shutdown() 后,由于线程需要运行 3秒 结束,awaitTermination() 只等待 1秒 就返回线程池状态,所以返回false
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown4 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
2,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
threadPoolExecutor.execute(new MyRun("2"));
try {
threadPoolExecutor.shutdown();
// 由于线程需要运行3秒结束,这里只等待1秒就返回线程池状态,所以返回false
boolean res = threadPoolExecutor.awaitTermination(1,TimeUnit.SECONDS);
System.out.println(res);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread.interrupted();
System.out.println(name+"--结束");
}
}
}
例子2
执行 shutdown() 后,线程需要运行 3秒 结束, awaitTermination() 等待5秒返回线程池状态,所以返回true
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown5 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
2,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
threadPoolExecutor.execute(new MyRun("2"));
try {
threadPoolExecutor.shutdown();
// 线程需要运行3秒结束,这里等待5秒返回线程池状态,所以返回true
boolean res = threadPoolExecutor.awaitTermination(5,TimeUnit.SECONDS);
System.out.println(res);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread.interrupted();
System.out.println(name+"--结束");
}
}
}
例子3
执行 shutdownNow() 后,抛出 java.lang.InterruptedException 异常,awaitTermination() 立即返回true
package ThreadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Shutdown6 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
2,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue(1)
);
threadPoolExecutor.execute(new MyRun("1"));
threadPoolExecutor.execute(new MyRun("2"));
try {
// 执行 shutdownNow() 后,抛出 java.lang.InterruptedException 异常,awaitTermination() 立即返回true
threadPoolExecutor.shutdownNow();
boolean res = threadPoolExecutor.awaitTermination(5,TimeUnit.SECONDS);
System.out.println(res);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyRun implements Runnable {
String name;
public MyRun(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"--开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread.interrupted();
System.out.println(name+"--结束");
}
}
}
参考:
https://blog.csdn.net/u012168222/article/details/52790400
https://blog.csdn.net/thetimelyrain/article/details/106902289
https://juejin.cn/post/6996665200711565319