使用volatile实现直接不使用打断标记,而是通过一个stop变量实现线程打断效果,当调用stop方法时,会将stop值设为true,监控线程会时刻监视stop的值,但是这种“假打断”的方式会有缺点,当线程执行到sleep时,虽然stop值已经置为true,但是还是需要等待sleep执行结束,开始执行下一次循环的时候才能退出,所以可以调用interrupt方法真正的打断,这种情况仔细考虑下其实做法很巧妙,如果监控线程正常运行,那么interrupt方法打断只是改变了打断标记,不做处理即可,因为本例的业务逻辑也不涉及利用打断标记。而如果确实是在sleep过程中被打断,那么会进入catch块中,catch块不做处理即可,还是会进入下一次循环。

    1. public class TestTwoPhases {
    2. public static void main(String[] args) throws InterruptedException {
    3. TwoPhaseTermination tpt = new TwoPhaseTermination();
    4. //创建线程,监控该线程状态,
    5. tpt.start();
    6. Thread.sleep(3500);
    7. //停止线程,但优雅地停止,选择interrupt线程;
    8. tpt.stop();
    9. }
    10. }
    11. //监控类
    12. class TwoPhaseTermination{
    13. private Thread monitor;
    14. private volatile boolean stop = false;//判读是否应该打断,不采用打断标记的形式
    15. //启动监控线程
    16. public void start(){
    17. //java基础,调用start方法,这里的monitor即指当前对象的monitor属性,与this.monitor等价
    18. monitor = new Thread(()->{
    19. while(true){
    20. if(stop){//stop为真,代表确实应该中断
    21. System.out.println("料理后事");
    22. break;
    23. }
    24. try {
    25. Thread.sleep(1000);//打断情况1
    26. System.out.println("执行监控记录");//打断情况2
    27. } catch (InterruptedException e) {
    28. }
    29. }
    30. });
    31. monitor.start();
    32. }
    33. // 停止监控线程
    34. public void stop(){
    35. stop=true;//应该打断
    36. monitor.interrupt();//也可以自己主动设置打断,为了防止sleep一直等待。
    37. }
    38. }

    监控线程和停止监控线程是两个线程,所以一个线程改主内存内stop的值,另一个线程读stop值。这涉及线程的可见性问题,所以stop要用volatile关键字修饰。