每个线程上都会有一个打断标记,默认是false,当别的线程打断某个线程后打断标记就会变为true。

打断机制提供了一种让线程1更友好的去结束别的线程的方式: 线程1打断线程2相当于给线程2发了一个信号,

线程2自己决定收到这个信号时要做的处理。

一、打断相关的方法

和打断相关的方法有如下几个

1.1 实例方法interrupt

Thread类中的实例方法java.lang.Thread#interrupt,用来打断一个线程,例如t1.interrupt() 会把正常运行的线程t1的打断标记变为true

1.2 实例方法isInterrupted

Thread类中的实例方法java.lang.Thread#isInterrupted() ,返回线程的打断标记值

1.3 静态方法interrupted

Thread类中的静态方法 java.lang.Thread#interrupted,返回当前线程的打断标记值并清空打断状态,

也就是说哪个线程的代码中调用了此方法,就返回打断状态,并且如果打断状态是true还会把它变成false。

@Slf4j
public class ThreadTest3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    log.info("打断状态: {}",Thread.currentThread().isInterrupted());
                    if(Thread.interrupted()) {//标记是true时才会进if,因为这方法会清空打断标记,
                        //所以内部再次获取打断标记值为false
                        log.info("被打断了,调用Thread.interrupted()后的打断状态: {}",Thread.currentThread().isInterrupted());
                        break;
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();//打断t1
    }
}

二、打断正常运行的线程

打断正常运行的线程仅会修改被打断线程的打断标记,不会影响线程的运行,需要被打断线程自己来处理被打断后的逻辑,像上边1.3中案例一样。

三、打断阻塞状态的线程

3.1 打断调用sleep,wait方法后陷入阻塞的线程

sleep,wait方法被打断时会抛出InterruptedException 异常,同时会清空打断标记,也就是这时获取打断标记得到的是false。

@Slf4j
public class ThreadTest3 {


    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //先获取锁,然后调用wait方法阻塞
                synchronized (ThreadTest3.class) {
                    try {
                        log.info("t1运行");
                        //在锁对象上调用wait方法阻塞
                        ThreadTest3.class.wait();
                    } catch (InterruptedException e) {
                        //被打断后会抛出InterruptedException
                        e.printStackTrace();
                        //并且会清空打断标记,也就是这时获取打断标记得到的是false,
                        log.info("获取打断标记:{}",Thread.currentThread().isInterrupted());
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();//打断t1
    }
}

3.2打断调用LockSupport.park()进入阻塞的线程

打断调用LockSupport.park()进入阻塞的线程,会使用这个线程恢复运行,并且打断标记的值会是true,

但要注意的是在打断标记是true的情况下再次调用park方法并不能使线程进入阻塞状态,只有清空打断标记后才能重新park线程到阻塞状态。

public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                log.info("t1 run");
                LockSupport.park();
                log.info("t1 after park1,打断标记: {}",Thread.currentThread().isInterrupted());
                //第一次打断后在打断标记是true的情况下再次park不起作用,
                LockSupport.park();
                log.info("t1 after park2");
                log.info("先获取再清空打断标记:{}",Thread.interrupted());//这个方法会先获取打断标记再清空打断标记
                LockSupport.park();//现在就可以park住线程使其进入阻塞状态了
                log.info("t1 after park3");

            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();//打断t1
    }