两阶段终止模式
两阶段终止模式
在并发时,如何让一个线程T1优雅地终止线程T2,优雅指的是给T2一个料理后事的机会。
方法1——利用interrupt
@Slf4j(topic = "c.two")
public class MyTwoInterrupt_ByInterrupt {
public static void main(String[] args) throws InterruptedException {
TwoInterruptTermination termination = new TwoInterruptTermination();
termination.start();
Thread.sleep(3500);
termination.stop();
}
}
@Slf4j(topic = "c.two")
class TwoInterruptTermination {
private Thread thread;
public void start() {
thread = new Thread(() -> {
while (true) {
log.debug("执行监控");
Thread currentThread = Thread.currentThread();
if (currentThread.isInterrupted()) {
log.debug("料理后事");
break;
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
currentThread.interrupt(); //让程序有料理后事的过程,优雅
}
}
}
});
thread.start();
}
public void stop() {
thread.interrupt();
}
}
方法2——park配合inturrupt
- park配合inturrupt使用,优雅的暂停、继续线程
- park只能打断一次:park进程通过inturrupt继续运行之后,打断标志为true,无法继续打断
- 通过interrupted方法设置打断标志为false,才能继续调用park方法,打断
方法 | 作用域 | 作用 |
---|---|---|
interrupted() | static | 判断当前线程是否被打断,清除打断标记——设置打断标记为false |
park() | LockSupport | 线程暂停,让出cpu |
interrupt() | 非static | 打断线程 |
private static void main(String[] args) throws Exception{
Thread t = new Thread(()->{
log.debug("暂停之前");
LockSupport.park();
log.debug("打断状态:{}", Thread.isInterrupt());
});
t.start();
try {Thread.sleep(1000);} catch(Exception e) {}
t.interrupt();
}
运行结果:
暂停之前
(等待一秒)
打断状态:true
问题:如果打断标记已经是 true, 再次 park 会失效
解决方法:可以使用 Thread.interrupted() 清除打断状态
private static void main(String[] args) throws Exception{
Thread t = new Thread(()->{
for(int i=0; i<4; i++) {
log.debug("parking");
LockSupport.park();
+log.debug("打断状态:{}", Thread.interrupted());
}
});
t.start();
try {Thread.sleep(1000);} catch(Exception e) {}
t.interrupt();
}
结果:
暂停之前
打断状态:true
暂停之前
打断状态:true
暂停之前
打断状态:true
暂停之前
打断状态:true