JAVA線程池ScheduledExecutorService周期性地執行任務 與單個Thread周期性執行任務的異常處理


本文記錄:

1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法執行周期性任務的過程,討論了在任務周期執行過程中出現了異常,會導致周期任務失敗。

2,使用普通的Thread類來執行任務,在main線程中周期性創建線程,提交任務。然后,使用UncaughtExceptionHandler來處理異常。 

 

一,正常任務執行

負責執行任務的線程類如下:(一個計算階乘的任務,計算5以上的階乘,就會拋出異常)

 1 public class FactorialCalc implements Runnable {
 2 
 3     private Integer number;
 4 
 5     public FactorialCalc(Integer number) {
 6         this.number = number;
 7     }
 8 
 9     public void run() {
10 
11         int result = 1;
12 
13         if (number == 0) {
14             System.out.println("0!=" + "1");
15         }
16 
17         if (number > 5) {
18             System.out.println("exception");
19             throw new IllegalArgumentException(">5");
20         }
21 
22         for(int i = 1; i <= number; i++) {
23             result *= i;
24 
25         }
26         System.out.println(number + "!=" + result);
27     }
28 }

 

測試的Main類如下:

 1 public class MainPeriod {
 2 
 3     public static void main(String[] args) {
 4 
 5         ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
 6 
 7         FactorialCalc task1 = new FactorialCalc(6);
 8         FactorialCalc task2 = new FactorialCalc(3);
 9 
10         ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);
11 //       ScheduledFuture<?> result =  executorService.scheduleAtFixedRate(task2, 0, 2, TimeUnit.SECONDS);
12 
13         try {
14             TimeUnit.SECONDS.sleep(5);
15             executorService.shutdown();
16         } catch (InterruptedException e) {
17             e.printStackTrace();
18         }
19     }
20 }

 

ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);

提交一個Runnable任務,延遲為0,每1秒鍾執行一次。

 

二,線程 執行過程中出現異常

當提交 task1 時,線程在執行過程中會拋出異常。

        FactorialCalc task1 = new FactorialCalc(6);//計算6的階乘,6大於5

        ScheduledFuture<?> result = executorService.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);

此時,如果注釋掉 //executorService.shutdown(); 則線程池不會中止,因為這是一個線程池,所有的異常都由線程池catch住了但是由於線程執行過程中拋出了異常,任務也不會周期性地執行了。參考JDK里面的scheduleAtFixedRate注釋:

 * If any execution of the task * encounters an exception, subsequent executions are suppressed. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

 

三,關閉線程池 ,執行 executorService.shutdown() 語句

若線程池線程 執行任務過程中拋出了異常,但是在 主線程中 執行了executorService.shutdown() 語句,則會正常關閉 線程池。

 

四,總結

使用ScheduledExecutorService的 scheduleAtFixedRate 方法執行周期性任務時,如果任務一直正常執行,則任務會按設定的執行周期一直在運行(前提是,主線程內不要調用executorService.shutdown() ,比如需要 執行 永久性的周期性任務,那就不能調用 executorService.shutdown() )。

如果任務在某次執行過程中拋出了異常,則周期性任務會被中斷,后續也不會再生成任務了,如果主線程 也沒有 調用 executorService.shutdown() ,那線程池就不會關閉了。

 

五,使用Thread類執行任務,在Main線程中通過while循環周期性提交任務,使用UncaughtExceptionHandler來處理異常

 1 import java.util.Random;
 2 import java.util.concurrent.TimeUnit;
 3 
 4 public class Main {
 5 
 6     public static void main(String[] args) {
 7         
 8         Random rand = new Random();
 9         
10         while(true){
11             int number = rand.nextInt(10);
12             Thread t = new Thread(new FactorialCalc(number));
13             t.setUncaughtExceptionHandler(new ExceptionHandler());
14             t.start();
15             try{
16                 System.out.println("sleep 4s for next task");
17                 TimeUnit.SECONDS.sleep(4);
18             }catch(InterruptedException e){
19                 
20             }
21         }
22     }
23 }

 在main方法中使用一個while(true)循環,周期性地創建線程 提交任務。

第12-13行,每創建一個線程,調用setUncaughtExceptionHandler方法設置異常處理。關於異常處理,可參考:JAVA線程未捕獲異常處理

第15-18行,線程每隔4s提交一次任務,從而實現任務的周期性執行。 

 

異常處理類ExceptionHandler類實現了UncaughtExceptionHandler接口,然后在uncaughtException方法里面定義具體的異常處理過程即可。

import java.lang.Thread.UncaughtExceptionHandler;

public class ExceptionHandler implements UncaughtExceptionHandler{

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("illegal exception: 計算的階乘大於5了," + e.getMessage());
    }
}

 

與線程池方式相比 ,這種方式是每個周期,都要new一個線程。而線程池則是每個周期new一個任務,把任務提交給線程池即可。

原文:http://www.cnblogs.com/hapjin/p/7616068.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM