这次这个的思路是在主类中维护一个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. JDK源码阅读(一):Object源码分析

    最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...

  2. HTTP、HTTPS常用的默认端口号

    端口号标识了一个主机上进行通信的不同的应用程序. 1.HTTP协议代理服务器常用端口号:80/8080/3128/8081/9098 2.SOCKS代理协议服务器常用端口号:1080 3.FTP(文件 ...

  3. scrapy基础知识之 CrawlSpiders:

    通过下面的命令可以快速创建 CrawlSpider模板 的代码: scrapy genspider -t crawl spidername xx.com LinkExtractors class sc ...

  4. 什么是Task

    什么是Task Task是.Net4.0新增用来处理异步编程的,叫做基于“任务编程模型”,任务其实是架构在线程之上的,具体操作的时候还是由线程去执行的,任务的管控有点类似于线程池,程序中开10个Tas ...

  5. IDEA永久使用

    IDEA永久使用 一.在https://www.cnblogs.com/zyx110/p/10799387.html中下载下面图片中箭头所指的部分 下载完成后双击打开,除了以下图片提示内容,一路下一步 ...

  6. web前端笔试篇(一)

    [ 题外话 ]:本博主作为一名准毕业生,即将面临毕业就业问题,即将到大四了,不准备考研的我,那么该去干嘛呢?毫无疑问,那就是实习,那么即使是实习,那么在要想进入自己心仪的企业之前,笔试这一关终究是无法 ...

  7. Vmware centos7无法联网的问题解决

    VMware三种网络连接方式的区别 : 1) bridge : 默认使用VMnet0,不提供DHCP服务 在桥接模式下,虚拟机和宿主计算机处于同等地位,虚拟机就像是一台真实主机一样存在于局域网中.因此 ...

  8. python取数字、字母

    python取数字.字母 有一串字符串“lxa7YzU”,其中有大写字母.小写字母和数字,现编写一脚本使得实现以下功能: 将这串字符串中的数字.大写字母.小写字母分别取出来并进行分类. 脚本如下所示: ...

  9. UTF—8与UTF—8(无bom)格式

    BOM——Byte Order Mark,就是字节序标记 在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF.而FFFE在U ...

  10. 初探Oracle全栈虚拟机---GraalVM

    官方说明: GraalVM是一个生态系统和共享运行时,不仅提供基于JVM的语言(如Java,Scala,Groovy和Kotlin)的性能优势,还提供其他编程语言(如JavaScript,Ruby,P ...