• ExecutorService生命周期(转)


    ExecutorService接口继承了Executor接口,定义了一些生命周期的方法

    Java代码  收藏代码
    1. public interface ExecutorService extends Executor {  
    2. void shutdown();  
    3. List<Runnable> shutdownNow();  
    4. boolean isShutdown();  
    5. boolean isTerminated();  
    6. boolean awaitTermination(long timeout, TimeUnit unit)  
    7.         throws InterruptedException;  
    8. }  

    本文,我们逐一分析里面的每个方法。

    首先,我们需要创建一个任务代码,这段任务代码主要是随机生成含有10个字符的字符串

    Java代码  收藏代码
    1. /** 
    2.  * 随机生成10个字符的字符串 
    3.  * @author dream-victor 
    4.  * 
    5.  */  
    6. public class Task1 implements Callable<String> {  
    7.   
    8.     @Override  
    9.     public String call() throws Exception {  
    10.         String base = "abcdefghijklmnopqrstuvwxyz0123456789";  
    11.         Random random = new Random();  
    12.         StringBuffer sb = new StringBuffer();  
    13.         for (int i = 0; i < 10; i++) {  
    14.             int number = random.nextInt(base.length());  
    15.             sb.append(base.charAt(number));  
    16.         }  
    17.         return sb.toString();  
    18.     }  
    19.   
    20. }  

     然后,我们还需要一个长任务,这里我们默认是沉睡10秒,

    Java代码  收藏代码
    1. /** 
    2.  * 长时间任务 
    3.  *  
    4.  * @author dream-victor 
    5.  *  
    6.  */  
    7. public class LongTask implements Callable<String> {  
    8.   
    9.     @Override  
    10.     public String call() throws Exception {  
    11.         TimeUnit.SECONDS.sleep(10);  
    12.         return "success";  
    13.     }  
    14.   
    15. }  

    OK,所有前期准备完毕,下面我们就来分析一下ExecutorService接口中和生命周期有关的这些方法:

    1、shutdown方法:这个方法会平滑地关闭ExecutorService,当我们调用这个方法时,ExecutorService停止接受 任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后 将会关闭ExecutorService。这里我们先不举例在下面举例。

    2、awaitTermination方法:这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程 等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。 一般情况下会和shutdown方法组合使用。例如:

    Java代码  收藏代码
    1. ExecutorService service = Executors.newFixedThreadPool(4);  
    2. service.submit(new Task1());  
    3. service.submit(new Task1());  
    4. service.submit(new LongTask());  
    5. service.submit(new Task1());  
    6.   
    7. service.shutdown();  
    8.   
    9. while (!service.awaitTermination(1, TimeUnit.SECONDS)) {  
    10.     System.out.println("线程池没有关闭");  
    11. }  
    12. System.out.println("线程池已经关闭");  

     这段代码中,我们在第三次提交了一个长任务,这个任务将执行10秒沉睡,紧跟着执行了一次shutdown()方法,假设:这时 ExecutorService被立即关闭,下面调用service.awaitTermination(1, TimeUnit.SECONDS)方法时应该返回true,程序执行结果应该只会打印出:“线程池已经关闭”。但是,真实的运行结果如下:

    Java代码  收藏代码
    1. 线程池没有关闭  
    2. 线程池没有关闭  
    3. 线程池没有关闭  
    4. 线程池没有关闭  
    5. 线程池没有关闭  
    6. 线程池没有关闭  
    7. 线程池没有关闭  
    8. 线程池没有关闭  
    9. 线程池没有关闭  
    10. 线程池已经关闭  

     这说明我们假设错误,service.awaitTermination(1, TimeUnit.SECONDS)每隔一秒监测一次ExecutorService的关闭情况,而长任务正好需要执行10秒,因此会在前9秒监测时 ExecutorService为未关闭状态,而在第10秒时已经关闭,因此第10秒时输出:线程池已经关闭。这也验证了shutdown方法关闭 ExecutorService的条件。

    3、shutdownNow方法:这个方法会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务,这个方法返回一个List列表,列表中返回的是等待在工作队列中的任务。例如:

    Java代码  收藏代码
    1. ExecutorService service = Executors.newFixedThreadPool(3);  
    2. service.submit(new LongTask());  
    3. service.submit(new LongTask());  
    4. service.submit(new LongTask());  
    5. service.submit(new LongTask());  
    6. service.submit(new LongTask());  
    7.   
    8. List<Runnable> runnables = service.shutdownNow();  
    9. System.out.println(runnables.size());  
    10.   
    11. while (!service.awaitTermination(1, TimeUnit.MILLISECONDS)) {  
    12.     System.out.println("线程池没有关闭");  
    13. }  
    14. System.out.println("线程池已经关闭");  

     这段代码中,我们限制了线程池的长度是3,提交了5个任务,这样将有两个任务在工作队列中等待,当我们执行shutdownNow方法 时,ExecutorService被立刻关闭,所以在service.awaitTermination(1, TimeUnit.MILLISECONDS)方法校验时返回的是false,因此没有输出:线程池没有关闭。而在调用shutdownNow方法时,我 们接受到了一个List,这里包含的是在工作队列中等待执行的任务,由于线程池长度为3,且执行的都是长任务,所以当提交了三个任务后线程池已经满了,剩 下的两次提交只能在工作队列中等待,因此我们看到runnables的大小为2,结果如下:

    Java代码  收藏代码
    1. 2  
    2. 线程池已经关闭  

    4、isTerminated方法:这个方法会校验ExecutorService当前的状态是否为“TERMINATED”即关闭状态,当为“TERMINATED”时返回true否则返回false。例如:

    Java代码  收藏代码
    1. ExecutorService service = Executors.newFixedThreadPool(3);  
    2. service.submit(new Task1());  
    3. service.submit(new Task1());  
    4. service.submit(new LongTask());  
    5.   
    6. service.shutdown();  
    7. System.out.println(System.currentTimeMillis());  
    8. while (!service.isTerminated()) {  
    9. }  
    10. System.out.println(System.currentTimeMillis());  

    这段代码我们执行了两个正常的任务和一个长任务,然后调用了shutdown方法,我们知道调用shutdown方法并不会立即关闭 ExecutorService,这时我们记录一下监测循环执行前的时间,在没有关闭前我们一直进入一个空循环中,直到 ExecutorService关闭后退出循环,这里我们知道长任务执行时间大约为10秒,我们看一下上述程序运行结果:

    Java代码  收藏代码
    1. 1303298818621  
    2. 1303298828634  
    3. 相差:10013毫秒,转换一下除以1000,得到相差大约10秒  

    这10秒正好是长任务执行的时间,因此在 ExecutorService正常关闭后isTerminated方法返回true。

    5、isShutdown方法:这个方法在ExecutorService关闭后返回true,否则返回false。方法比较简单不再举例。

    以上讨论是基于ThreadPoolExecutor的实现,不同的实现会有所不同需注意。

  • 相关阅读:
    100+ Python挑战性编程练习(1)
    python面试题--初级(二)
    python面试题--初级(一)
    centos查看iptables和firewall防火墙状态、开启、关闭防火墙
    Keepalived nginx HA负载均衡
    windows10安装SQLServer 2008 R2详细说明
    CentOS安装mysql5.7
    centOS7.5安装docker
    redis哨兵选举算法--raft
    CentOS7.5安装GitLab及汉化
  • 原文地址:https://www.cnblogs.com/cornucopia/p/4499418.html
Copyright © 2020-2023  润新知