每个线程上都会有一个打断标记,默认是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
}