文章目录
- 打断标记
 - 两阶段终止
 - 注意
 - 打断park线程
 
打断标记
睡眠中的线程被打断时,会抛出异常,把打断标记置为false,而不是变为true,wait和join也是。
打断 sleep,wait,join 的线程
 这几个方法都会让线程进入阻塞状态
 打断 sleep 的线程, 会清空打断状态,以 sleep 为例。
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test1")
public class st2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep..");
            try {
                Thread.sleep(1000); // wait join
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("打断");
        t1.interrupt();
        System.out.println("打断标记=" + t1.isInterrupted());
    }
}
 

而打断正常线程时,其实并没有打断,只是改变打断标记,线程还会继续运行,需要我们手动利用打断标记的布尔值去判断进行打断。
@Slf4j(topic = "c.Test3")
public class st3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    log.debug("打断标记判断为真,退出循环");
                    break;
                }
            }
        }, "t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("打断");
        t1.interrupt();
    }
}
 

两阶段终止
在了解完打断后,我们可以知道,打断正常和阻塞中的线程时,情况是不一样的,想要利用打断标记停止一个线程,要考虑两种情况,正常就不用说了,在睡眠时,被打断后,打断标记重置为false,所以在异常处理中,再打断一次,即可改变打断标记,随后的循环中结束线程。

package com.leran;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test3")
public class st3 {
    public static void main(String[] args) throws InterruptedException {
        TwoInt twoInt = new TwoInt();
        twoInt.start();
        Thread.sleep(3000);
        twoInt.stop();
    }
}
@Slf4j(topic = "c.TwoInt")
class TwoInt {
    private Thread t1;
    public void start() {
        t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    log.debug("被打断");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    log.debug("监控");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt(); // 重新打断一次,在正常运行状态下
                }
            }
        }, "t1");
        t1.start();
    }
    public void stop(){
        t1.interrupt();
    }
}
 

注意
isInterrupt() 判断是否打断不会清空打断标记。
 interrupted() 是静态方法,和上面功能一样,但是会清空打断标记。
打断park线程
park是LockSupport类中的静态方法,用于暂停当前线程,处于wait状态。
只有打断标记为true的线程才能被park。
@Slf4j(topic = "c.Test3")
public class st3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("park");
            LockSupport.park();
            log.debug("unpark");
            log.debug("打断标记=" + Thread.currentThread().isInterrupted()); // true;
            LockSupport.park(); // true  无法park
            log.debug("unpark"); // 直接会运行这个
        }, "t1");
        t1.start();
        Thread.sleep(1000);
        t1.interrupt(); // 打断
    }
}
 

看起来和打断正常运行的线程差不多。
第二个park未执行,因为打断标记未true,可以用Thread.interrupted()获取后重置标记。
@Slf4j(topic = "c.Test3")
public class st3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("park");
            LockSupport.park();
            log.debug("unpark");
            log.debug("打断标记=" + Thread.interrupted()); // true ,然后重置为false
            LockSupport.park(); // true  无法park
            log.debug("unpark"); // 直接会运行这个
        }, "t1");
        t1.start();
        Thread.sleep(1000);
        t1.interrupt(); // 打断
    }
}
 




















