使用volatile实现直接不使用打断标记,而是通过一个stop变量实现线程打断效果,当调用stop方法时,会将stop值设为true,监控线程会时刻监视stop的值,但是这种“假打断”的方式会有缺点,当线程执行到sleep时,虽然stop值已经置为true,但是还是需要等待sleep执行结束,开始执行下一次循环的时候才能退出,所以可以调用interrupt方法真正的打断,这种情况仔细考虑下其实做法很巧妙,如果监控线程正常运行,那么interrupt方法打断只是改变了打断标记,不做处理即可,因为本例的业务逻辑也不涉及利用打断标记。而如果确实是在sleep过程中被打断,那么会进入catch块中,catch块不做处理即可,还是会进入下一次循环。
public class TestTwoPhases {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination tpt = new TwoPhaseTermination();
//创建线程,监控该线程状态,
tpt.start();
Thread.sleep(3500);
//停止线程,但优雅地停止,选择interrupt线程;
tpt.stop();
}
}
//监控类
class TwoPhaseTermination{
private Thread monitor;
private volatile boolean stop = false;//判读是否应该打断,不采用打断标记的形式
//启动监控线程
public void start(){
//java基础,调用start方法,这里的monitor即指当前对象的monitor属性,与this.monitor等价
monitor = new Thread(()->{
while(true){
if(stop){//stop为真,代表确实应该中断
System.out.println("料理后事");
break;
}
try {
Thread.sleep(1000);//打断情况1
System.out.println("执行监控记录");//打断情况2
} catch (InterruptedException e) {
}
}
});
monitor.start();
}
// 停止监控线程
public void stop(){
stop=true;//应该打断
monitor.interrupt();//也可以自己主动设置打断,为了防止sleep一直等待。
}
}
监控线程和停止监控线程是两个线程,所以一个线程改主内存内stop的值,另一个线程读stop值。这涉及线程的可见性问题,所以stop要用volatile关键字修饰。