zoukankan      html  css  js  c++  java
  • 如何停止一个线程池?

    Java 并发工具包中 java.util.concurrent.ExecutorService 接口定义了线程池任务提交、获取线程池状态、线程池停止的方法等。

    JDK 1.8 中,线程池的停止一般使用 shutdown()、shutdownNow()、shutdown() + awaitTermination(long timeout, TimeUnit unit) 方法。

    1、shutdown() 方法源码中解释

         * Initiates an orderly shutdown in which previously submitted
         * tasks are executed, but no new tasks will be accepted.
         * Invocation has no additional effect if already shut down.
    • 有序关闭,已提交任务继续执行
    • 不接受新任务

    2、shutdownNow() 方法源码中解释

         * Attempts to stop all actively executing tasks, halts the
         * processing of waiting tasks, and returns a list of the tasks
         * that were awaiting execution.
    • 尝试停止所有正在执行的任务
    • 停止等待执行的任务,并返回等待执行的任务列表

    3、awaitTermination(long timeout, TimeUnit unit) 方法源码中解释

      * Blocks until all tasks have completed execution after a shutdown
         * request, or the timeout occurs, or the current thread is
         * interrupted, whichever happens first.
         *
         * @param timeout the maximum time to wait
         * @param unit the time unit of the timeout argument
         * @return {@code true} if this executor terminated and
         *         {@code false} if the timeout elapsed before termination
         * @throws InterruptedException if interrupted while waiting
    • 收到关闭请求后,所有任务执行完成、超时、线程被打断,阻塞直到三种情况任意一种发生
    • 参数可以设置超时时间与超时单位
    • 线程池关闭返回 true;超过设置时间未关闭,返回 false

    实践:

    1、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 shutdown() 方法

    package constxiong.concurrency.a013;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试固定数量线程池 shutdown() 方法
     * @author ConstXiong
     */
    public class TestFixedThreadPoolShutdown {
        
        public static void main(String[] args) {
            //创建固定 3 个线程的线程池
            ExecutorService threadPool = Executors.newFixedThreadPool(3);
            
            //向线程池提交 10 个任务
            for (int i = 1; i <= 10; i++) {
                final int index = i;
                threadPool.submit(() -> {
                    System.out.println("正在执行任务 " + index);
                    //休眠 3 秒
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            
            //休眠 4 秒
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            //关闭线程池
            threadPool.shutdown();
        }
    
    }

    打印结果如下,可以看出,主线程向线程池提交了 10 个任务,休眠 4 秒后关闭线程池,线程池把 10 个任务都执行完成后关闭了。

    正在执行任务 1
    正在执行任务 3
    正在执行任务 2
    正在执行任务 4
    正在执行任务 6
    正在执行任务 5
    正在执行任务 8
    正在执行任务 9
    正在执行任务 7
    正在执行任务 10

    2、使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 shutdownNow() 方法

    package constxiong.concurrency.a013;
    
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试固定数量线程池 shutdownNow() 方法
     * @author ConstXiong
     */
    public class TestFixedThreadPoolShutdownNow {
        
        public static void main(String[] args) {
            //创建固定 3 个线程的线程池
            ExecutorService threadPool = Executors.newFixedThreadPool(3);
            
            //向线程池提交 10 个任务
            for (int i = 1; i <= 10; i++) {
                final int index = i;
                threadPool.submit(() -> {
                    System.out.println("正在执行任务 " + index);
                    //休眠 3 秒
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            
            //休眠 4 秒
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            //关闭线程池
            List<Runnable> tasks = threadPool.shutdownNow();
            System.out.println("剩余 " + tasks.size() + " 个任务未执行");
        }
    
    }

    打印结果如下,可以看出,主线程向线程池提交了 10 个任务,休眠 4 秒后关闭线程池,线程池执行了 6 个任务,抛出异常,打印返回的剩余未执行的任务个数。

    正在执行任务 1
    正在执行任务 2
    正在执行任务 3
    正在执行任务 4
    正在执行任务 6
    正在执行任务 5
    剩余 4 个任务未执行
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at constxiong.concurrency.a013.TestFixedThreadPoolShutdownNow.lambda$0(TestFixedThreadPoolShutdownNow.java:24)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

    3、Executors.newFixedThreadPool(int nThreads) 创建固定大小线程池,测试 awaitTermination(long timeout, TimeUnit unit) 方法

    package constxiong.concurrency.a013;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 测试固定数量线程池 shutdownNow() 方法
     * @author ConstXiong
     */
    public class TestFixedThreadPoolAwaitTermination {
        
        public static void main(String[] args) {
            //创建固定 3 个线程的线程池
            ExecutorService threadPool = Executors.newFixedThreadPool(3);
            
            //向线程池提交 10 个任务
            for (int i = 1; i <= 10; i++) {
                final int index = i;
                threadPool.submit(() -> {
                    System.out.println("正在执行任务 " + index);
                    //休眠 3 秒
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
            
            //关闭线程池,设置等待超时时间 3 秒
            System.out.println("设置线程池关闭,等待 3 秒...");
            threadPool.shutdown();
            try {
                boolean isTermination = threadPool.awaitTermination(3, TimeUnit.SECONDS);
                System.out.println(isTermination ? "线程池已停止" : "线程池未停止");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //再等待超时时间 20 秒
            System.out.println("再等待 20 秒...");
            try {
                boolean isTermination = threadPool.awaitTermination(20, TimeUnit.SECONDS);
                System.out.println(isTermination ? "线程池已停止" : "线程池未停止");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

    打印结果如下,可以看出,主线程向线程池提交了 10 个任务,申请关闭线程池 3 秒超时,3 秒后线程池并未成功关闭;再获取线程池关闭状态 20 秒超时,线程池成功关闭。

    正在执行任务 1
    正在执行任务 3
    正在执行任务 2
    设置线程池关闭,等待 3 秒...
    线程池未停止
    正在执行任务 4
    正在执行任务 6
    再等待 20 秒...
    正在执行任务 5
    正在执行任务 7
    正在执行任务 9
    正在执行任务 8
    正在执行任务 10
    线程池已停止

    总结:

    1、调用 shutdown() 和 shutdownNow() 方法关闭线程池,线程池都无法接收新的任务

    2、shutdown() 方法会继续执行正在执行未完成的任务;shutdownNow() 方法会尝试停止所有正在执行的任务

    3、shutdown() 方法没有返回值;shutdownNow() 方法返回等待执行的任务列表

    4、awaitTermination(long timeout, TimeUnit unit) 方法可以获取线程池是否已经关闭,需要配合 shutdown() 使用

    5、shutdownNow() 不一定能够立马结束线程池,该方法会尝试停止所有正在执行的任务,通过调用 Thread.interrupt() 方法来实现的,如果线程中没有 sleep() 、wait()、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。

     来一道刷了进BAT的面试题?

  • 相关阅读:
    自定义ckeditor5
    ckEditor5 图片上传到七牛云
    Vue2.0原理-指令
    小程序体积优化(1)--优化大文本
    win10系统安装docker注意事项
    Vue2.0原理-模板解析
    使用nginx部署静态网站
    react-native初体验(2) — 认识路由
    react-native初体验(1) — hello world
    领骑衫总结
  • 原文地址:https://www.cnblogs.com/ConstXiong/p/11686330.html
Copyright © 2011-2022 走看看