Java——检测其他线程的状态以及启动已死亡的线程
这次这个的思路是在主类中维护一个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——检测其他线程的状态以及启动已死亡的线程的更多相关文章
- Java线程:创建与启动
Java线程:创建与启动 一.定义线程 1.扩展java.lang.Thread类. 此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 R ...
- JAVA中线程的状态
java thread的运行周期中, 有几种状态, 在 java.lang.Thread.State 中有详细定义和说明: NEW:至今尚未启动的线程的状态. RUNNABLE:可运行线程的线程状态. ...
- java中线程的状态详解
一.线程的五种状态 线程的生命周期可以大致分为5种,但这种说法是比较旧的一种说法,有点过时了,或者更确切的来说,这是操作系统的说法,而不是java的说法.但对下面所说的六种状态的理解有所帮助,所以 ...
- 并发基础(四) java中线程的状态
一.程的五种状态 线程的生命周期可以大致分为5种,但这种说法是比较旧的一种说法,有点过时了,或者更确切的来说,这是操作系统的说法,而不是java的说法.但对下面所说的六种状态的理解有所帮助,所以也 ...
- Java多线程之线程的状态迁移
Java多线程之线程的状态迁移 下图整理了线程的状态迁移.图中的线程状态(Thread.Stat 中定义的Enum 名)NEW.RUNNABLE .TERMINATED.WAITING.TIMED_W ...
- 【Java并发编程】:并发新特性—Executor框架与线程池
Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...
- juc线程池原理(四): 线程池状态介绍
<Thread之一:线程生命周期及五种状态> <juc线程池原理(四): 线程池状态介绍> 线程有5种状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态.线程池也有5种状态 ...
- 用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)
1.概述 在Java中,我们一般通过集成Thread类和实现Runnnable接口,调用线程的start()方法实现线程的启动.但如果并发的数量很多,而且每个线程都是执行很短的时间便结束了,那样频繁的 ...
- java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器
多线程并发就像是内功,框架都像是外功,内功不足,外功也难得精要. 1.进程和线程的区别 一个程序至少有一个进程,一个进程至少有一个线程. 用工厂来比喻就是,一个工厂可以生产不同种类的产品,操作系统就是 ...
随机推荐
- CSDN,CNBLOGS博客文章一键转载插件(转载测试)
插件地址: https://greasyfork.org/zh-CN/scripts/381053-csdn%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0%E8%BD%AC% ...
- python3 连接数据库注意点
类库:pymysql ''' Created on 2019年 @author: Root ''' import pymysql from name import getName # 数据库连接信息 ...
- Hash碰撞概率
计算Hash冲突的概率 虽然已经很多可以选择的Hash函数,但创建一个好的Hash函数仍然是一个活跃的研究领域.一些Hash函数是快的,一些是慢的,一些Hash值均匀地分布在值域上,一些不是.对于我们 ...
- centos 5.2 php升级
# gedit /etc/yum.repos.d/utterramblings.repo [utterramblings] name=Jason's Utter Ramblings Repo base ...
- Windows下必备的开发神器之Cmder使用说明
诚言,对于开发码字者,Mac和Linux果断要比Windows更贴心;但只要折腾下,Windows下也是有不少利器的.之前就有在Windows下效率必备软件一文中对此做了下记载:其虽没oh-my-zs ...
- 使用docker搭建gitlab服务器
简单记录Docker的使用和GitLab的搭建 Docker基础篇 没有sudo权限 安装docker 基础命令 docker安装mysql和配置 Dockerfile常用命令 制作镜像 发布镜像 容 ...
- Excel催化剂开源第49波-Excel与PowerBIDeskTop互通互联之第三篇
在PowerBIDeskTop开启的SSAS服务,和Sqlserver所开启的一个本质的区别是,前者其端口号是随机生成的,即上一次打开获得的端口号,下一次关闭后再打开,系统分配给它新的端口号,而后者因 ...
- 面试题((A)null).fun()——java中null值的强转
面试题分享 public class A {public static void fun1() { System.out.println("fun1"); } public voi ...
- [leetcode] 55. Jump Game (Medium)
原题 题目意思即 每一格代表你当前最多能再往后跳几次,从第一格开始,如果能跳到最后一格返回true,反之为false. 思路:用一个下标记录当前最多能跳到哪一格,遍历一遍 --> 如果当前格子不 ...
- webstorm mac 版破解
一.打开终端,输入: sudo vim /etc/hosts 回车后输入密码,编辑 hosts 文件,如图: 二.进入编辑模式(按 i 键),在最后一行添加如下代码: 0.0.0.0 account. ...