这次这个的思路是在主类中维护一个map,map的key是线程名,value是线程的状态,然后创建周期执行的线程通过检测这个map来判断进程的状态,如果有死亡的进程就把该进程启动。
首先是主类,这里的main方法中为了执行结果简单易懂 ,先是初始化了一个长度为2的newFixedThreadPool线程池,然后提交了2个任务(这个任务类下面会有介绍),然后启动监控线程,这个监控线程也是一会介绍,其他方法的作用注释写得也很清楚:
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的时候抛异常):
/** * 测试线程 */ 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,有死亡的线程就启动该线程。
/** * 监控线程 */ 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的时候死亡了,然后会被监控进程启动。