线程池调度java_java使⽤默认线程池踩过的坑
场景
⼀个调度器,两个调度任务,分别处理两个⽬录下的txt⽂件,某个调度任务应对某些复杂问题的时候会持续特别长的时间,甚⾄有⼀直阻塞的可能。我们需要⼀个manager来管理这些task,当这个task的上⼀次执⾏时间距离现在超过5个调度周期的时候,就直接停掉这个线程,然后再重启它,保证两个⽬标⽬录下没有待处理的txt⽂件堆积。
重要的英语
问题
直接使⽤java默认的线程池调度task1和task2.由于外部txt的种种不可控原因,导致task2线程阻塞。现象就是task1和线程池调度器都正常运⾏着,但是task2迟迟没有动作。
当然,找到具体的阻塞原因并进⾏针对性解决是很重要的。但是,这种措施很可能并不能完全、彻底、全⾯的处理好所有未知情况。我们需要保证任务线程或者调度器的健壮性!
⽅案计划
线程池调度器并没有原⽣的针对被调度线程的业务运⾏状态进⾏监控处理的API。因为task2是阻塞在我们的业务逻辑⾥的,所以最好的⽅式是写⼀个TaskManager,所有的任务线程在执⾏任务前全部到这个TaskManager这⾥来注册⾃⼰。这个TaskManager就负责对于每个⾃⼰管辖范围内的task进⾏实时全程监控!精彩句子摘抄
后⾯的重点就是如何处理超过5个执⾏周期的task了。
⽅案如下:
●⼀旦发现这个task线程,⽴即中⽌它,然后再次重启;
●⼀旦发现这个task线程,直接将整个pool清空并停⽌,重新放⼊这两个task ——【task明确的情况下】;⽅案实施
中⽌后重启
●Task实现类
class FileTask extends Thread {
private long lastExecTime=0;
protected long interval=10000;
public long getLastExecTime() {
return lastExecTime;
}
public void tLastExecTime(long lastExecTime) {
this.lastExecTime= lastExecTime;
}
public long getInterval() {
return interval;
}
public void tInterval(long interval) {
this.interval= interval;
}
public File[] getFiles() {
return null;
}
●Override
public void run() {努力加油的简单句子
while (!Thread.currentThread().isInterrupted()) {
条包lastExecTime=System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " is running ->" + new Date()); try {
Thread.sleep(getInterval() * 6 * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace(); // 当线程池shutdown之后,这⾥就会抛出exception了
}
}
}
}
●TaskManager
public class TaskManager implements Runnable {
private final static Log Log(TaskManager .class);
public Setrunners=newCopyOnWriteArraySet();
ExecutorService wCachedThreadPool();
public void registerCodeRunnable(FileTask process) {
runners.add(process);
}
public TaskManager (Setrunners) {蓝玫瑰的花语是什么
this.runners= runners;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
long current=System.currentTimeMillis();
for (FileTask wrapper : runners) {
if (current - LastExecTime() &Interval() * 5) {
wrapper.interrupt();
for (File file : Files()) {
file.delete();
}
一个乞丐wrapper.start();
}
}
} catch (Exception e1) {
<("Error happens when we trying to interrupt and restart a task ");
}
黄鹤楼公园
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
什么叫域名
}
这段代码会报错 java.lang.Thread IllegalThreadStateException。为什么呢?其实这是⼀个很基础的问题,您应该不会像我⼀样马虎。查看Thread.start()的注释, 有这样⼀段:
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
是的,⼀个线程不能够启动两次。那么它是怎么判断的呢?
public synchronized void start() {
/**
* A zero status value corresponds to state "NEW". 0对应的是state NEW
*/
if (threadStatus != 0) //如果不是NEW state,就直接抛出异常!
throw new IllegalThreadStateException();
group.add(this);
boolean started=fal;
try {
start0(); // 启动线程的native⽅法
started=true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
恩,只有是NEW状态才能够调⽤native⽅法启动⼀个线程。好吧,到这⾥了,就普及也⾃补⼀下jvm⾥的线程状态:
所有的线程状态::
●NEW —— 还没有启动过
●RUNNABLE —— 正在jvm上运⾏着
●BLOCKED —— 正在等待锁/信号量被释放
●WAITING —— 等待其他某个线程的某个特定动作
●TIMED_WAITING —— A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
●TERMINATED —— 退出,停⽌
线程在某个时间点上只可能存在⼀种状态,这些状态是jvm⾥的,并不反映操作系统线程的状态。查⼀下Thread的API,没有对其状态进⾏修改的API。那么这条路是不通的吗?
仔细考虑⼀下……
如果把任务做成Runnable实现类,然后在把这个实现类丢进线程池调度器之前,利⽤此Runnable构造⼀个Thread,是不是这个Thread对象就能够控制这个runnable对象,进⽽控制在线程池中运⾏着的task了呢?⾮也!让我们看看Thread和ThreadPoolExecutor对Runnable 的处理吧。
●Thread
/* What will be run. */
private Runnable target;
结合上⾯的start()⽅法,很容易猜出,start0()会把target弄成⼀个线程来进⾏运⾏。
●ThreadPoolExecutor
public void execute(Runnable command) {
if (command== null)
throw new NullPointerException();
int ();
if (workerCountOf(c)
if (addWorker(command, true))