在使用线程池的时候,ExecutorService提供了两种关闭线程池的方法,shutdown()和shutdownNow(),先不墨迹,直接写出这两个方法的作用:
- 使用shutdown正常关闭
将线程池状态置为SHUTDOWN,线程池并不会立即停止:
- 停止接收外部submit的任务
- 内部正在跑的任务和队列里等待的任务,会执行完
- 等到第二步完成后,才真正停止
- 使用shutdownNow强行关闭
将线程池状态置为STOP。企图立即停止,事实上不一定:
- 跟shutdown()一样,先停止接收外部提交的任务
- 忽略队列里等待的任务
- 尝试将正在跑的任务interrupt中断
- 返回未执行的任务列表
shutdownNow()它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,调用interrupt()方法并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息,interrupt()只能响应可中断的阻塞,对于不可中断的阻塞,我们需要找到线程阻塞的原因并特殊处理。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。
shutdown()可以和awaitTermination()方法一起使用
awaitTermination()方法的作用:
当前线程阻塞,直到
- 等所有已提交的任务(包括正在跑的和队列中等待的)执行完
- 或者等超时时间到
- 或者线程被中断,抛出InterruptedException
然后返回true(shutdown请求后所有任务执行完毕)或false(已超时)
下面用代码解释三个方法的使用
- shutdown()
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ShutTest {
public static void main(String[] args) {
//核心池3,最大池6
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(2));
//创建5个线程
for (int i= 0;i<5;i++){
executor.submit(()->{
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
executor.submit(()->{
System.out.println("after shutdown");
});
}
}
输出结果:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7cca494b rejected from java.util.concurrent.ThreadPoolExecutor@7ba4f24f[Shutting down, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.springcloud.server.springserver.ShutTest.main(ShutTest.java:32)
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-2
pool-1-thread-3
从输出结果看到,输出了5个线程的打印,其中3个是线程池里面的,有2个是在队列里面的,也就是说正在运行的和队列里面的任务全部可以执行完成,在shutDown()之后提交,会报错,执行拒绝默认的策略.
2.shutdownNow()
package com.springcloud.server.springserver;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ShutTest {
public static void main(String[] args) {
//核心池3,最大池6
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(2));
//创建8个线程
for (int i= 0;i<5;i++){
executor.submit(()->{
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"interrupted");
}
});
}
List<Runnable> runnables = executor.shutdownNow();
System.out.println(runnables);
executor.submit(()->{
System.out.println("after shutdown");
});
}
}
输出结果:
从输出结果看到,输出了3个线程的打印,其中3个是线程池里面的,有2个是在队列里面的,在shutDownNow()之后提交,队列里面的2个线程直接被忽略,停止启动,并且以Runnable的形式返回到list集合里面.线程池里面的三个线程因为interrupt()方法,抛出InterruptedException,继续提交的任务也不会执行,而是抛出异常.
3.awaitTermination()
package com.springcloud.server.springserver;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ShutTest {
public static void main(String[] args) throws InterruptedException {
//核心池3,最大池6
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(2));
//创建8个线程
for (int i= 0;i<3;i++){
executor.submit(()->{
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"interrupted");
}
});
}
boolean b = executor.awaitTermination(3, TimeUnit.SECONDS);
System.out.println(b);
System.out.println("after awaitTermination");
executor.submit(()->{
System.out.println("after shutdown");
});
executor.shutdown();
boolean a = executor.awaitTermination(3, TimeUnit.SECONDS);
System.out.println(a);
}
}
awaitTermination()是阻塞的,返回结果是线程池是否已停止(已经停止就是true,此含义包括线程池已经shutdown并且没有还在运行的线程),awaitTermination并不是用来关闭线程池,它只是用来检测timeout时间后线程池是否关闭。线程池关闭之后就会返回true,一般在调用shutdown()方法后调用.