ThreadPoolExecutor 中的 shutdown() 、shutdownNow() 、awaitTermination() 的用法和区别

在使用线程池的时候,ExecutorService提供了两种关闭线程池的方法,shutdown()和shutdownNow(),先不墨迹,直接写出这两个方法的作用:

  • 使用shutdown正常关闭

将线程池状态置为SHUTDOWN,线程池并不会立即停止:

  1. 停止接收外部submit的任务
  2. 内部正在跑的任务和队列里等待的任务,会执行完
  3. 等到第二步完成后,才真正停止
  • 使用shutdownNow强行关闭

将线程池状态置为STOP。企图立即停止,事实上不一定:

  1. 跟shutdown()一样,先停止接收外部提交的任务
  2. 忽略队列里等待的任务
  3. 尝试将正在跑的任务interrupt中断
  4. 返回未执行的任务列表

shutdownNow()它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,调用interrupt()方法并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息,interrupt()只能响应可中断的阻塞,对于不可中断的阻塞,我们需要找到线程阻塞的原因并特殊处理。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。

shutdown()可以和awaitTermination()方法一起使用

awaitTermination()方法的作用:

当前线程阻塞,直到

  1. 等所有已提交的任务(包括正在跑的和队列中等待的)执行完
  2. 或者等超时时间到
  3. 或者线程被中断,抛出InterruptedException
    然后返回true(shutdown请求后所有任务执行完毕)或false(已超时)

下面用代码解释三个方法的使用

  1. 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()方法后调用.

 

 

 

 

 

 

 

  • 16
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`java.util.concurrent.ThreadPoolExecutor`是Java用于管理线程池的类。`shutdown()`和`shutdownNow()`都是用于关闭线程池的方法,但它们之间有一些区别。 - `shutdown()`方法:该方法将线程池状态设置为SHUTDOWN,不再接受新任务,但会等待所有已经提交的任务执行完成后再关闭线程池。如果在调用`shutdown()`方法后又提交了新任务,这些新任务将会被拒绝执行并抛出`RejectedExecutionException`异常。 - `shutdownNow()`方法:该方法将线程池状态设置为STOP,不再接受新任务,并尝试停止所有正在执行的任务,包括等待执行的任务。该方法会尝试断正在执行的任务,如果任务无法被断,则会保持运行状态。该方法返回一个`List<Runnable>`,其包含所有等待执行的任务。 以下是一个示例代码,演示了如何使用`ThreadPoolExecutor`类以及如何使用`shutdown()`和`shutdownNow()`方法: ```java import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExample { public static void main(String[] args) throws InterruptedException { // 创建一个线程池,最多同时执行2个任务 ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); // 提交5个任务 for (int i = 0; i < 5; i++) { executor.submit(new Task(i)); } // 关闭线程池 executor.shutdown(); // 等待所有任务执行完成 executor.awaitTermination(1, TimeUnit.MINUTES); // 输出线程池状态 System.out.println("线程池状态:" + (executor.isTerminated() ? "已关闭" : "未关闭")); // 再次提交任务,会抛出RejectedExecutionException异常 executor.submit(new Task(5)); // 关闭线程池 executor.shutdownNow(); // 输出线程池状态 System.out.println("线程池状态:" + (executor.isTerminated() ? "已关闭" : "未关闭")); } static class Task implements Runnable { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Task " + taskId + " is interrupted"); } System.out.println("Task " + taskId + " is completed"); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值