监控任务的生命周期
场景描述
Thread提供了可获取状态、以及判断状态是否alive的方法。然而,这些方法均是针对线程本身的,我们提交的任务在运行过程中所处的状态是无法直接获取的,例如什么时候开始,什么时候结束。
解决方案
观察者模式
当某个对象发生状态改变需要通知第三方时,观察者模式适合这样的工作。应用观察者模式时,使用Thread作为事件源(引发状态发生变化的源头)。Thread作为任务的逻辑单元掌握整个过程的始末。事件的接受者则是接收通知的一方。
接口定义
Observable接口
该接口主要是暴露给调用者使用,其中四个枚举类型分别代表了当前任务执行生命周期的各个阶段。
public interface Observable {
enum Cycle{
STARTED,RUNNING,DONE,ERROR
}
/**
* 获取当前线程的生命周期状态
*/
Cycle getCycle();
/**
* 定义启动线程的方法,主要是为了平布Thread的其他方法
*/
void start();
/**
* 定义线程中断的方法,作用域start一样,也是为了屏蔽Thread的其他方法
*/
void interrupt();
}
TaskLifeCycle接口
TaskLifeCycle接口定义了在任务执行的生命周期中会被处罚的接口,其中EmptyLifeCycle是一个空的实现,主要是为了让市容这保持对Thread类的使用习惯。
public interface TaskLifeCycle<T> {
/**
* 任务启动时会触发onStart方法
* @param thread
*/
void onStart(Thread thread);
/**
* 任务正在运行时会触发onRunning方法
* @param thread
*/
void onRunning(Thread thread);
/**
* 任务运行结束时触发onFinish方法,其中result是任务执行结束后的结果
* @param thread
* @param result
*/
void onFinish(Thread thread,T result);
/**
* 任务执行报错时会触发onError方法
* @param thread
* @param e
*/
void onError(Thread thread,Exception e);
/**
* 生命周期接口的空实现(Adapter)
* @param <T>
*/
class EmptyLifecycle<T> implements TaskLifeCycle<T>{
@Override
public void onStart(Thread thread) {
}
@Override
public void onRunning(Thread thread) {
}
@Override
public void onFinish(Thread thread, T result) {
}
@Override
public void onError(Thread thread, Exception e) {
}
}
}
Task接口
监控任务的生命周期是要对线程中的任务执行增加可观察能力,并且需要获得最后的计算结果(即需要监控的对象就是Task的实例)。因此Runnable接口在可观察的线程中将不再被使用,以Task接口取代,它的作用于Runnable类似,主要用于承载任务的执行逻辑单元。
public interface Task<T> {
/**
* 任务执行的接口,改接口允许有返回值。类似于Runnable中的 run()
* @return
*/
T call();
}
ObservableThread实现
ObservableThread是任务监控的关键,它继承Thread类和Observable接口,在构造期间传入Task的具体实现。
public class ObservableThread<T> extends Thread implements Observable {
/**
* 事件的监听者。原始的观察者模式这里应该是Observer的集合。
*/
private final TaskLifeCycle<T> lifeCycle;
private final Task<T> task;
private Cycle cycle;
/**
* 指定Task的实现,默认情况下使用EmptyLifeCycle
*
* @param task
*/
public ObservableThread(Task<T> task) {
this(new TaskLifeCycle.EmptyLifecycle<>(), task);
}
public ObservableThread(TaskLifeCycle<T> lifeCycle, Task<T> task) {
super();
if (task == null) {
throw new IllegalArgumentException("The task is required.");
}
this.lifeCycle = lifeCycle;
this.task = task;
}
/**
* 重写父类的run方法,并将其修饰为final类型,不允许子类再次对其进行重写。
* run方法在线程的运行期间,可监控任务在执行过程中的各个生命周期阶段,任务每经过一个
* 阶段就相当于发生一次事件。
*/
@Override
public final void run(){
//在执行线程逻辑单元的时候,分别触发相应的事件
this.update(Cycle.STARTED, null, null);
try{
this.update(Cycle.RUNNING,null ,null );
T result = this.task.call();
this.update(Cycle.DONE, result, null);
}catch (Exception e){
/**
* 捕获Task运行时所产生的异常,将错误向监听者发送。
*/
this.update(Cycle.ERROR, null, e);
}
}
@Override
public Cycle getCycle() {
return this.cycle;
}
/**
* update方法用于通知事件的监听者,此任务在执行过程中发生了什么,最主要的
* 是通知异常的处理。
* @param cycle
* @param result
* @param e
*/
private void update(Cycle cycle,T result,Exception e){
this.cycle = cycle;
if (lifeCycle == null){
return;
}
try{
switch (cycle){
case STARTED:
this.lifeCycle.onStart(currentThread());
break;
case RUNNING:
this.lifeCycle.onRunning(currentThread());
break;
case DONE:
this.lifeCycle.onFinish(currentThread(), result);
break;
case ERROR:
this.lifeCycle.onError(currentThread(), e);
break;
}
}catch (Exception ex){
/**
* 监听者也就是TaskLifeCycle,在响应某个事件的过程中出现了意外,
* 则会导致任务的正常执行受到影响,因此需要进行捕获,并忽略这些异常
* 信息以保证TaskLifeCycle的实现不影响Task的正确执行,但是如果
* 是Task在执行过程中出现了异常,则需要把这个异常抛出,保持与call方法
* 同样的意图。
*/
if (cycle == Cycle.ERROR){
throw ex; //Task执行时出现的异常
}else{
// 监听者出现的异常,丢弃
}
}
}
}
运行测试
ObservableThread的实现已经完成,首先关注ObservableThread是否保持了与Thread的使用习惯,其次再去关注是否可以实现TaskLifeCycle去监听感兴趣的时间,比如获取最终的计算结果。
public static void main(String[] args) {
/**
* ObservableThread -> Thread
* Task -> Runnable
* call -> run
*/
Observable observableThread = new ObservableThread<>(new Task() {
@Override
public Object call() {
try{
System.out.println("running");
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("finished done.");
return null;
}
});
observableThread.start();
下面这个例子定义了一个需要返回值的ObservableThread,重写了TaskLifeCycle中的方法。
public static void main(String[] args) {
TaskLifeCycle<String> lifeCycle = new TaskLifeCycle<String>() {
@Override
public void onStart(Thread thread) {
System.out.println("start Task");
}
@Override
public void onRunning(Thread thread) {
System.out.println("Task is running");
int i = 1/0; // 监听者产生异常
}
@Override
public void onFinish(Thread thread, String result) {
System.out.println("finish");
System.out.println("result is "+result);
}
@Override
public void onError(Thread thread, Exception e) {
e.printStackTrace();
}
};
Observable observableThread = new ObservableThread<String>(lifeCycle, new Task<String>() {
@Override
public String call() {
try{
TimeUnit.SECONDS.sleep(2);
// int i = 1/0; // Task产生异常
}catch (InterruptedException e){
e.printStackTrace();
}
return "Hello Observer";
}
});
observableThread.start();
}
或者只实现部分方法。
TaskLifeCycle<String> lifeCycle = new TaskLifeCycle.EmptyLifecycle<String>() {
@Override
public void onFinish(Thread thread, String result) {
System.out.println("finish");
System.out.println("result is "+result);
}
};
ThreadPoolExecutor.runWorker()
在JUC中,ThreadPoolExecutor代表了一个线程池,其中runWorker() 方法是执行任务的方法。其中调用了beforeExecute() 、afterExecute() 和terminated() 方法来扩展任务的执行。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
总结
- 接口Observable中定义了与Thread同样的方法用于屏蔽Thread中的其他API。这就是为什么在使用过程中用Observable声明ObservableThread对象。
- 将ObservableThread中的run方法修饰为final,或者将ObservableThread类修饰为final,防止子类继承重写,导致整个生命周期的监控失效。
- ObservableThread中的run方法充当了事件源的发起者,TaskLifeCycle是监听者,是事件回调的响应者。
Reference
《Java高并发编程详解》