这次这个的思路是在主类中维护一个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的时候死亡了,然后会被监控进程启动。

Java——检测其他线程的状态以及启动已死亡的线程的更多相关文章

  1. Java线程:创建与启动

    Java线程:创建与启动 一.定义线程   1.扩展java.lang.Thread类.   此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...

  2. JAVA中线程的状态

    java thread的运行周期中, 有几种状态, 在 java.lang.Thread.State 中有详细定义和说明: NEW:至今尚未启动的线程的状态. RUNNABLE:可运行线程的线程状态. ...

  3. java中线程的状态详解

    一.线程的五种状态   线程的生命周期可以大致分为5种,但这种说法是比较旧的一种说法,有点过时了,或者更确切的来说,这是操作系统的说法,而不是java的说法.但对下面所说的六种状态的理解有所帮助,所以 ...

  4. 并发基础(四) java中线程的状态

    一.程的五种状态   线程的生命周期可以大致分为5种,但这种说法是比较旧的一种说法,有点过时了,或者更确切的来说,这是操作系统的说法,而不是java的说法.但对下面所说的六种状态的理解有所帮助,所以也 ...

  5. Java多线程之线程的状态迁移

    Java多线程之线程的状态迁移 下图整理了线程的状态迁移.图中的线程状态(Thread.Stat 中定义的Enum 名)NEW.RUNNABLE .TERMINATED.WAITING.TIMED_W ...

  6. 【Java并发编程】:并发新特性—Executor框架与线程池

    Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...

  7. juc线程池原理(四): 线程池状态介绍

    <Thread之一:线程生命周期及五种状态> <juc线程池原理(四): 线程池状态介绍> 线程有5种状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态.线程池也有5种状态 ...

  8. 用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)

    1.概述 在Java中,我们一般通过集成Thread类和实现Runnnable接口,调用线程的start()方法实现线程的启动.但如果并发的数量很多,而且每个线程都是执行很短的时间便结束了,那样频繁的 ...

  9. java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器

    多线程并发就像是内功,框架都像是外功,内功不足,外功也难得精要. 1.进程和线程的区别 一个程序至少有一个进程,一个进程至少有一个线程. 用工厂来比喻就是,一个工厂可以生产不同种类的产品,操作系统就是 ...

随机推荐

  1. struts2入门Demo

    一.引入必要的jar包,所需jar包如下: 二.配置web.xml.主要目的是拦截请求 <?xml version="1.0" encoding="UTF-8&qu ...

  2. 免费rar/zip解压缩工具BandZip

    今天为大家推荐一款解压缩类软件--BandZip bandzip是我认为的最好用的解压缩软件,速度快没广告 能够秒杀其他的压缩类软件 下载地址 bandzip点我 1 BandZip简介 BandZi ...

  3. Java编程思想:I/O的典型使用方式

    import java.io.*; public class Test { public static void main(String[] args) { // BufferedInputFile. ...

  4. [笨方法学Python]ImportError"No module named bin.app"【笔记】

    运行nosetests时,出现:ImportError"No module named bin.app" 解决方法: 1.检查路径是否是bin/app.py 2.检查是否创建bin ...

  5. 新手小白快速登天日记之安装python以及环境变量和pycharm解释器较为详细教程

    Python解释器安装及环境变量配置 Python官方网站:www.python.org 首先打开这个网址,找到downloads选择,因为我是Windows所以下载windows的,因电脑而异 然后 ...

  6. C#5.0新增功能02 调用方信息

    连载目录    [已更新最新开发文章,点击查看详细] 通过使用调用方信息特性,可获取有关方法的调用方的信息. 可以获取源代码的文件路径.源代码中的行号和调用方的成员名称. 此信息有助于跟踪.调试和创建 ...

  7. [leetcode] 263. Ugly Number (easy)

    只要存在一种因数分解后,其因子是2,3,5中的一种或多种,就算是ugly数字. 思路: 以2/3/5作为除数除后,最后结果等于1的就是ugly数字 Runtime: 4 ms, faster than ...

  8. Hadoop学习-hdfs安装及其一些操作

    hdfs:分布式文件系统 有目录结构,顶层目录是:  /,存的是文件,把文件存入hdfs后,会把这个文件进行切块并且进行备份,切块大小和备份的数量有客户决定. 存文件的叫datanode,记录文件的切 ...

  9. C语言编程入门之--第一章初识程序

    第一章 初识程序 导读:计算机程序无时不刻的影响着人类的生活,现代社会已经离不开程序,程序的作用如此巨大,那么程序到底是什么呢?本章主要讨论程序的概念,唤起读者对程序的兴趣,同时对C语言程序与其它语言 ...

  10. python常见模块-collections-time-datetime-random-os-sys-序列化反序列化模块(json-pickle)-subprocess-03

    collections模块-数据类型扩展模块 ''' 在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque ...