此次這個的思路是在主類中維護一個map,map的key是線程名,value是線程的狀態,而後建立週期執行的線程經過檢測這個map來判斷進程的狀態,若是有死亡的進程就把該進程啓動。測試
首先是主類,這裏的main方法中爲了執行結果簡單易懂 ,先是初始化了一個長度爲2的newFixedThreadPool線程池,而後提交了2個任務(這個任務類下面會有介紹),而後啓動監控線程,這個監控線程也是一會介紹,其餘方法的做用註釋寫得也很清楚:this
public class Test { /** Log4j 初始化 */ private static final Logger logger = LoggerFactory.getLogger(Test.class); /** 標誌線程存活的變量 */ public static final int THREAD_STATUS_ALIVE = 1; /** 標誌線程死亡的變量 */ public static final int THREAD_STATUS_DEAD = 0; /** 記錄每一個線程的狀態的map */ private static HashMap<String,Integer> threadStatesMap = new HashMap<String, Integer>(); /** 線程池的長度*/ private static int threadPoolLength; /** 建立固定長度的線程池 */ private static ExecutorService executor; public static void main(String[] args) { /** 初始化線程池 */ executor = Executors.newFixedThreadPool(2); /** 提交Task給線程池 */ for(int i = 1; i <= 2; i++){ executeToPool(new EtlTask(i)); } Monitor monitor = new Monitor(); /** 啓動檢測線程 */ monitor.start(); } /** * 根據線程名,更新線程的狀態 * @param threadName * @param status */ public synchronized static void alterThreadStatesMap(String threadName,Integer status){ threadStatesMap.put(threadName,status); } /** * 返回ThreadStatesMap的長度 * @return */ public static int getThreadStatesMapSize(){ return threadStatesMap.size(); } /** * 返回key對應ThreadStatesMap的value * @param key * @return ThreadStatesMapValueByKey */ public static int getThreadStatesMapValueByKey(String key){ return threadStatesMap.get(key); } /** * 提交任務給線程池 * @param etlTask */ public static void executeToPool(EtlTask etlTask){ executor.execute(etlTask); } }
而後建立一個會報異常的測試類(id每一秒減一次1,到0的時候拋異常):spa
/** * 測試線程 */ class testThread { private static Logger logger = LoggerFactory.getLogger(testThread.class); public static void start(int id) throws Exception{ id = id + 5; while (true){ try { Thread.sleep(1000); }catch (Exception e){ e.printStackTrace(); } id = id - 1; if(id == 0){ //id每一秒減一次1,到0的時候拋異常 throw new Exception(); } logger.debug(Thread.currentThread().getName() + " is running result = " + id ); } } }
而後建立一個執行上面測試任務的任務類,這裏在第一次被啓動的時候會設置好該任務類的名字,將主類中的map中線程名對應的value設置爲THREAD_STATUS_ALIVE,而後開始執行上面的測試任務,若是有異常的話會將主類中的map中線程名對應的value設置爲THREAD_STATUS_DEAD:線程
/** * 任務線程 */ class EtlTask implements Runnable{ /** 組ID */ private int groupid ; /** 初始化組ID */ EtlTask(int groupid){ this.groupid = groupid; } public void run() { /** 設置線程名 */ Thread.currentThread().setName("G" + groupid); /** 設置線程的 運行狀態爲THREAD_STATUS_ALIVE 在ThreadStatesMap中*/ Test.alterThreadStatesMap(Thread.currentThread().getName(),Test.THREAD_STATUS_ALIVE); try{ /** 將組ID傳入,執行任務*/ testThread.start(groupid); }catch (Exception e ){ /** 出現異常 設置線程的 運行狀態爲THREAD_STATUS_DEAD 在ThreadStatesMap中*/ Test.alterThreadStatesMap(Thread.currentThread().getName(),Test.THREAD_STATUS_DEAD); } } }
最後就是監控類,這個類就是在遍歷主類中的map,有死亡的線程就啓動該線程。debug
/** * 監控線程 */ class Monitor extends Thread{ private static final Logger logger = LoggerFactory.getLogger(Monitor.class); public void run() { while(true){ try { Thread.sleep(5000);//監控線程阻塞5秒後運行 }catch (Exception e){ e.printStackTrace(); } logger.debug("Current total [" + Test.getThreadStatesMapSize() +"] threads"); /** 線程存活數 */ int alives = 0; /** 線程死亡數 */ int deads = 0; /** 遍歷ThreadStatesMap 計算線程存活數和死亡數 */ for(int i = 1;i <= Test.getThreadStatesMapSize();i++){ if(Test.getThreadStatesMapValueByKey("G" + i) == Test.THREAD_STATUS_ALIVE){ alives++; }else { deads++; } } logger.debug("Current the number of threads alive is [" + alives +"]"); logger.debug("Current the number of threads dead is [" + deads +"]"); /** 若是死亡線程數大於0 就啓動已經死亡的線程 */ if(deads > 0) { /** 遍歷ThreadStatesMap 將死亡的線程啓動 */ for (int i = 1; i <= Test.getThreadStatesMapSize(); i++) { if (Test.getThreadStatesMapValueByKey("G" + i) == Test.THREAD_STATUS_DEAD) { /** 向線程池提交任務 */ Test.executeToPool(new EtlTask(i)); logger.debug("Thread G" + i + "已被啓動"); } } } } } }
效果:日誌
2018-08-02 16:24:31,649 - G2 is running result = 6 2018-08-02 16:24:31,655 - G1 is running result = 5 2018-08-02 16:24:32,653 - G2 is running result = 5 2018-08-02 16:24:32,656 - G1 is running result = 4 2018-08-02 16:24:33,653 - G2 is running result = 4 2018-08-02 16:24:33,656 - G1 is running result = 3 2018-08-02 16:24:34,653 - G2 is running result = 3 2018-08-02 16:24:34,656 - G1 is running result = 2 2018-08-02 16:24:35,635 - Current total [2] threads 2018-08-02 16:24:35,635 - Current the number of threads alive is [2] 2018-08-02 16:24:35,635 - Current the number of threads dead is [0] 2018-08-02 16:24:35,654 - G2 is running result = 2 2018-08-02 16:24:35,657 - G1 is running result = 1 2018-08-02 16:24:36,654 - G2 is running result = 1 2018-08-02 16:24:40,635 - Current total [2] threads 2018-08-02 16:24:40,635 - Current the number of threads alive is [0] 2018-08-02 16:24:40,635 - Current the number of threads dead is [2] 2018-08-02 16:24:40,635 - Thread G1已被啓動 2018-08-02 16:24:40,635 - Thread G2已被啓動 2018-08-02 16:24:41,635 - G2 is running result = 6 2018-08-02 16:24:41,635 - G1 is running result = 5 2018-08-02 16:24:42,636 - G1 is running result = 4 2018-08-02 16:24:42,636 - G2 is running result = 5 2018-08-02 16:24:43,636 - G2 is running result = 4 2018-08-02 16:24:43,636 - G1 is running result = 3 2018-08-02 16:24:44,637 - G2 is running result = 3 2018-08-02 16:24:44,637 - G1 is running result = 2 2018-08-02 16:24:45,636 - Current total [2] threads 2018-08-02 16:24:45,636 - Current the number of threads alive is [2] 2018-08-02 16:24:45,636 - Current the number of threads dead is [0] 2018-08-02 16:24:45,637 - G1 is running result = 1 2018-08-02 16:24:45,637 - G2 is running result = 2 2018-08-02 16:24:46,637 - G2 is running result = 1 2018-08-02 16:24:50,636 - Current total [2] threads 2018-08-02 16:24:50,636 - Current the number of threads alive is [0] 2018-08-02 16:24:50,636 - Current the number of threads dead is [2] 2018-08-02 16:24:50,636 - Thread G1已被啓動 2018-08-02 16:24:50,636 - Thread G2已被啓動 2018-08-02 16:24:51,637 - G2 is running result = 6 2018-08-02 16:24:51,637 - G1 is running result = 5 2018-08-02 16:24:52,637 - G1 is running result = 4 2018-08-02 16:24:52,637 - G2 is running result = 5 Process finished with exit code -1
從控制檯的輸出日誌能夠看到,兩個線程的結果到0的時候死亡了,而後會被監控進程啓動。code