文章目录
- 打断标记
- 两阶段终止
- 注意
- 打断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(); // 打断
}
}