这篇实际上是跟上一篇想实现的功能一样,想完成线程状态的跟踪。但是为什么想采用这种方式来进行跟踪呢?主要是前面都是在try catch中捕获异常,然后因为异常导致的线程终止。那么其实实际的开发过程中,遇到的问题都不是前面遇到的问题,所以只能通过心跳的方式进行监控。
通过学习线程池,了解到了:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
这个线程池可以完成实现心跳检测的功能。
所以就想想用它来实现一个监听器的功能,定时的监听我开启的线程状态,如果某个线程出现异常或者死掉,就将该死掉的线程给重新启动。
于是就有了下面的代码:
监听器类:
import java.util.Map;
import java.util.concurrent.*;
/**
* 心跳检测,对线程进行监控。
*/
public class ThreadListener{
private ThreadPoolExecutor executor;
//线程容器key:线程名称,value:线程
private Map<String,Thread> threadMap;
public ThreadListener(){
}
public ThreadListener(ThreadPoolExecutor poolExecutor,Map threadMap){
this.executor = poolExecutor;
this.threadMap = threadMap;
}
//启动监听器方法,每2s执行一次监听
public void startListening(){
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
for (String s : threadMap.keySet()) {
System.out.println("线程:"+s+",状态:"+threadMap.get(s).isAlive());
}
}
},2,2,TimeUnit.SECONDS);
}
}
线程类:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* 通过心跳检测的方式时刻抓取线程池的线程状态
*/
public class ThreadTasks {
public static void main(String[] args) {
ThreadTasks t = new ThreadTasks();
t.ttt();
}
public void ttt(){
Map<String,Thread> threadMap = new HashMap<String,Thread>();
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 2,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
for (int i = 1; i <= 2; i++) {
TempTask tempTask = new TempTask("md"+i);
Thread task = new Thread(tempTask,tempTask.taskName);
poolExecutor.execute(task);
threadMap.put(tempTask.taskName,task);
}
//将线程纳入到监听中
ThreadListener threadListener = new ThreadListener(poolExecutor,threadMap);
threadListener.startListening();
}
class TempTask implements Runnable{
private String taskName;
public TempTask(){
}
public TempTask(String taskName){
this.taskName = taskName;
}
int count = 0;
public void run() {
while (true){
try {
Thread.sleep(1000);
count++;
if("md1".equals(taskName) && count == 5){
System.out.println("抛出异常");
throw new RuntimeException("我是异常..");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(taskName+"正在运行...");
}
}
}
}
好了,就是这么个简单的东西。本想着可以监听到线程的死亡状态。没曾想运行结果是这样的:
md1正在运行...
md2正在运行...
md1正在运行...
md2正在运行...
md1正在运行...
md2正在运行...
md1正在运行...
md2正在运行...
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 我是异常..
at com.listener.ThreadTasks$TempTask.run(ThreadTasks.java:50)
at java.lang.Thread.run(Thread.java:748)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
抛出异常
md2正在运行...
线程:md2,状态:false
线程:md1,状态:false
md2正在运行...
md2正在运行...
md2正在运行...
md2正在运行...
md2正在运行...
线程:md2,状态:false
线程:md1,状态:false
md2正在运行...
md2正在运行...
呃,为啥都是false。
细心的大家会发现,这里出现异常的线程是咱们定义的线程么,咱们定义的线程名称不是md1和md2么。通过源码,才发现原来线程池执行的线程并不是咱们传递进去的线程,而是重新从线程工厂取的。
//firstTask为传递的线程
w = new Worker(firstTask);
//t为开启的线程
final Thread t = w.thread;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
//实际上启动的是这个
this.thread = getThreadFactory().newThread(this);
}
到此,美好的想法彻底没戏了。那么此时我该如何监听呢?
这里想到的办法就是舍弃线程池,对上面的代码进行改造:
直接通过new Thread()的形式进行创建,同时将线程和任务分别存放在不同的map中。然后再监听器中判断状态,如果发现线程死掉,就重新启动一个线程,然后执行任务。
public class ThreadTasks {
public static void main(String[] args) {
ThreadTasks t = new ThreadTasks();
t.tttt();
}
public void tttt(){
Map<String,Thread> threadMap = new HashMap<String,Thread>();
Map<String,TempTask> taskMap = new HashMap<String,TempTask>();
for (int i = 1; i <= 2; i++) {
TempTask tempTask = new TempTask("md"+i);
Thread t = new Thread(tempTask,tempTask.taskName);
t.start();
threadMap.put(tempTask.taskName,t);
taskMap.put(tempTask.taskName,tempTask);
}
//将线程纳入到监听中
ThreadListener threadListener = new ThreadListener(null,threadMap,taskMap);
threadListener.startListening();
}
class TempTask implements Runnable{
private String taskName;
public TempTask(){}
public TempTask(String taskName){
this.taskName = taskName;
}
int count = 0;
public void run() {
while (true){
try {
Thread.sleep(1000);
count++;
if("md1".equals(taskName) && count == 5){
count++;
//throw new RuntimeException("我是异常..");
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(taskName+"正在运行...");
}
System.out.println(taskName+"停止运行...");
}
}
}
public class ThreadListener{
private ThreadPoolExecutor executor;
private Map<String,Thread> threadMap;
private Map<String,ThreadTasks.TempTask> taskMap;
public ThreadListener(){
}
public ThreadListener(ThreadPoolExecutor poolExecutor,Map threadMap,Map taskMap){
this.executor = poolExecutor;
this.threadMap = threadMap;
this.taskMap = taskMap;
}
public void startListening(){
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
ExecutorService executorService = Executors.newSingleThreadExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
for (String s : threadMap.keySet()) {
boolean isAlive = threadMap.get(s).isAlive();
System.out.println("线程:"+s+",状态:"+isAlive);
if(!isAlive){
threadMap.remove(s);//将死掉的线程清理
System.out.println("重启线程"+s);
Thread t = new Thread(taskMap.get(s),s);
threadMap.put(s,t);
executorService.execute(t);
}
}
}
},5,5,TimeUnit.SECONDS);
}
}
这种方式感觉有点儿low,有更好的方法可留言哈。