美文网首页互联网科技
正确执行与终止线程池的方法,你知道吗?

正确执行与终止线程池的方法,你知道吗?

作者: java菲菲 | 来源:发表于2019-10-08 17:06 被阅读0次

    01 通常线程池的执行方法有两种execute和submit,那么他们有什么区别呢?

    1.接受任务的类型

    execute 只能接受Runnable类型的任务

    void execute(Runnable command);

    submit不管是Runnable还是Callable类型的任务都可以接受,但是Runnable返回值均为void,所以使用Future的get()获得的还是null

    Future submit(Callable task); 
    
    Future submit(Runnable task, T result); 
    
    Future submit(Runnable task);
    

    2.execute方法适用于那些不需要关注返回值的场景,我们只需要把要执行的任务丢进线程池

    import java.util.concurrent.ExecutorService; 
    
    import java.util.concurrent.Executors; 
    
    public class Thread02 {  
    
              public static void main(String[] args) throws Exception {    
    
                                  ExecutorService pool = Executors.newFixedThreadPool(1);    
    
                                  pool.execute(() -> {        
    
                                          System.out.println("我爱学习,我爱java");    
    
                                   });  
    
              } 
    
    }
    
    运行结果:我爱学习,我爱java
    

    submit方法适用于需要关注返回值的场景,通常这种的我们在工作中用的比较多,可以通过Future的get()方法得到线程的运行结果

    import java.util.concurrent.Callable;    
    
    import java.util.concurrent.ExecutorService;    
    
    import java.util.concurrent.Executors;    
    
    import java.util.concurrent.Future;    
    
    public class Thread02 {    
    
               public static void main(String[] args) throws Exception {       
    
                                   ExecutorService pool = Executors.newFixedThreadPool(1);    
    
                                   //我们取一个String类型的返回值      
    
                                   Future future = pool.submit(new Callable() {         
    
                                               public String call() throws Exception {             
    
                                                          return "我爱java";        
    
                                                }      
    
                                   });      
    
                                  String result = future.get();      
    
                                  System.out.println("线程的运行结果为: " + result);            
    
                                  //我们取一个boolean类型的返回值      
    
                                  Future future2 = pool.submit(new Callable() {        
    
                                              public Boolean call() throws Exception {            
    
                                                         return 6 > 7;        
    
                                               }      
    
                                   });      
    
                                  System.out.println("线程的运行结果为:" + future2.get());      
    
                                  //取一个Runnable类型的任务      
    
                                  Future future3 = pool.submit(()->{        
    
                                              System.out.println();    
    
                                   });      
    
              }    
    
     }
    

    其运行结果为

    线程的运行结果为: 我爱java 
    
    线程的运行结果为:false 
    
    线程的运行结果为:null
    

    02 线程池执行后先让其停止有什么方法呢?通常线程池的停止方法有两种:shutdown()和shutdownNow(),那么他们又有什么区别呢?

    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. 
    
    * 
    
    *This method does not wait for previously submitted tasks to
    
    * complete execution.  Use {@link #awaitTermination awaitTermination} 
    
    * to do that. 
    
    * 
    
    * @throws SecurityException if a security manager exists and 
    
    *                shutting down this ExecutorService may manipulate 
    
    *                threads that the caller is not permitted to modify 
    
    *                because it does not hold {@link 
    
    *                java.lang.RuntimePermission}{@code ("modifyThread")}, 
    
    *                or the security manager's {@code checkAccess} method 
    
    *               denies access. 
    
    */
    
    void shutdown();
    
    image

    观看其源码的说明可以知道,shutdown()这种方法是有序的进行停止,在此之前提交的任务都可以继续执行,而执行此方法后如果继续往线程池丢任务,则不会再去执行任务。

    import java.util.concurrent.ExecutorService;
    
    import java.util.concurrent.Executors;
    
    public class Test01 {
    
               public static void main(String[] args) throws Exception {    
    
                          ExecutorService pool = Executors.newFixedThreadPool(1);    
    
                          for (int i = 0; i < 6; i++) {        
    
                                System.err.println(i);        
    
                                 pool.execute(() -> {            
    
                                          try {                
    
                                                 Thread.sleep(1000);                
    
                                                  System.out.println("我爱java,我爱学习");            
    
                                            } catch (Exception e) {                
    
                                                    e.printStackTrace();            
    
                                                }        
    
                                  });    
    
                           }    
    
                          Thread.sleep(2000);    
    
                          //停止线程池    
    
                          pool.shutdown();    
    
                          pool.execute(()->{        
    
                                  System.out.println("我不想上班");    
    
                           });  
    
            } 
    
    }
    

    运行结果

    0
    
    1
    
    2
    
    3
    
    4
    
    5
    
    我爱java,我爱学习 
    
    我爱java,我爱学习 
    
    Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.test.Test01$$Lambda$2/2129789493@27d6c5e0 rejected from java.util.concurrent.ThreadPoolExecutor@4f3f5b24[Shutting down, pool size = 1, active threads = 1, queued tasks = 3, completed tasks = 2]
    
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
    
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
    
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
    
    at com.test.Test01.main(Test01.java:22) 
    
    我爱java,我爱学习 
    
    我爱java,我爱学习 
    
    我爱java,我爱学习 
    
    我爱java,我爱学习
    

    通过测试我们先创建一个大小为1的线程池,往里面丢6个任务,然后调用shutdown()方法去停止线程池,最后我们再去执行一个任务

    可以发现我们刚开始放进去的任务都有序的执行了,当我们执行为shutdown()方法后,再去调用线程池,此时线程池已经不工作了。

    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. 
    
    * 
    
    *This method does not wait for actively executing tasks to 
    
    * terminate.  Use {@link #awaitTermination awaitTermination} to 
    
    * do that. 
    
    * 
    
    *There are no guarantees beyond best-effort attempts to stop 
    
    * processing actively executing tasks.  For example, typical 
    
    * implementations will cancel via {@link Thread#interrupt}, so any 
    
    * task that fails to respond to interrupts may never terminate. 
    
    * 
    
    * @return list of tasks that never commenced execution 
    
    * @throws SecurityException if a security manager exists and 
    
    *                 shutting down this ExecutorService may manipulate 
    
    *                 threads that the caller is not permitted to modify 
    
    *                 because it does not hold {@link 
    
    *                 java.lang.RuntimePermission}{@code ("modifyThread")}, 
    
    *                or the security manager's {@code checkAccess} method 
    
    *                denies access. 
    
    */
    
    List shutdownNow();
    
    image

    观看其源码的说明可以知道,shutdownNow()这种方法是停止所有线程(正在执行的和等待的),并返回任务列表(等待执行的任务),已经执行的任务是不会返回的,我们可以通过代码去验证

    import java.util.List; 
    
    import java.util.concurrent.ExecutorService; 
    
    import java.util.concurrent.Executors; 
    
    public class Test01 { 
    
               public static void main(String[] args) throws Exception {    
    
                          ExecutorService pool = Executors.newFixedThreadPool(1);    
    
                          for (int i = 0; i < 6; i++) {        
    
                                System.err.println(i);        
    
                                 pool.execute(() -> {            
    
                                         try {                
    
                                              //1秒执行一个                
    
                                              Thread.sleep(1000);                
    
                                               System.out.println("我爱java,我爱学习");            
    
                                            } catch (Exception e) {                
    
                                                         e.printStackTrace();            
    
                                                  }        
    
                                 });    
    
                          }    
    
                         //休眠两秒  
    
                        Thread.sleep(2000);  
    
                        List runnables= pool.shutdownNow();  
    
                        System.out.println("未执行的线程"+runnables);  
    
                        System.out.println("未执行的线程的数量"+runnables.size());  
    
            }
    
    }
    
    运行结果
    
    0 
    
    1 
    
    2 
    
    3  
    
    4 
    
    5 
    
    我爱java,我爱学习 
    
    我爱java,我爱学习 
    
    未执行的线程[com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235,    com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235] 
    
    未执行的线程的数量4
    

    通过上面代码演示,我们先放6个任务进如线程池,每秒执行一个,然后休眠2秒,通过运行结果我们可以知道在休眠的2秒钟执行了两个线程,所以还有四个线程未执行,输出结果为4;

    当我们把休眠时间变为2500毫秒(2.5秒)其输出结果为:

    0  
    
    1  
    
    2  
    
    3  
    
    4  
    
    5 
    
    我爱java,我爱学习 
    
    我爱java,我爱学习 
    
    未执行的线程[com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235] 
    
    未执行的线程的数量3 
    
    java.lang.InterruptedException: sleep interrupted 
    
    at java.lang.Thread.sleep(Native Method) 
    
    at com.test.Test01.lambda$main$0(Test01.java:14) 
    
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    
    at java.lang.Thread.run(Thread.java:745)
    

    可以看到当我们让其休眠2.5秒后。在这段时间执行完成了2个线程,第三个线程正在执行中(还未执行完),而shutdownNow()方法是停止所有线程(执行中的和等待执行的),返回正在等待执行的线程。所以其返回正在等待执行的数量为3

    相关文章

      网友评论

        本文标题:正确执行与终止线程池的方法,你知道吗?

        本文链接:https://www.haomeiwen.com/subject/gktipctx.html