为什么使用两阶段终止?在一个线程 T1 中如何“优雅”终止线程 T2?
这里的【优雅】指的是给 T2 一个料理后事的机会。两阶段终止模式是终止另一个线程中的一种解决方案。
1 错误思路
-
使用线程对象的 stop() 方法停止线程
- stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
-
使用 System.exit(int) 方法停止线程
- 目的仅是停止一个线程,但这种做法会让整个程序都停止
2. 两阶段终止模式
2.1 利用 isInterrupted
interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行
-
睡眠中被打断抛出异常,执行catch中的 c常,urrent.interrupt()置isInterrupted为true
-
正常执行被打断,不会抛出异常,stop中的interrupt方法置isInterrupted为true
class TPTInterrupt{
private Thread thread;
public void start(){
thread = new Thread(new Runnable() {
@Override
public void run() {
while (true){
//第二次被打断中止线程运行
if (Thread.currentThread().isInterrupted()){
System.out.println("第二次被打断");
break;
}
//睡眠中被打断,跑出异常,isInterrupted设置为true,但是线程不会停止
try {
System.out.println("running");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("第一次被打断");
Thread.currentThread().interrupt();
}
}
}
});
thread.start();
}
public void stop(){
thread.interrupt();
}
}
调用
public static void main(String[] args) {
TPTInterrupt tptInterrupt = new TPTInterrupt();
// 开始
tptInterrupt.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//5秒后interrupt打断线程执行
tptInterrupt.stop();
}
运行结果
running
第一次被打断
第二次被打断
2.2 利用停止标记
停止标记用 volatile 是为了保证该变量在多个线程之间的可见性
我们的例子中,即主线程把它修改为 true 对 t1 线程可见
代码实现
class TPTVolatile{
private volatile boolean flag = false;
private Thread thread;
public void start(){
thread = new Thread(new Runnable() {
@Override
public void run() {
while (true){
Thread currentThread = Thread.currentThread();
if (flag){
System.out.println("第二次被打断");
break;
}
try {
System.out.println("running");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("第一次被打断");
flag = true;
}
}
}
});
thread.start();
}
public void stop(){
flag = true;
thread.interrupt();
}
}
调用
public static void main(String[] args) {
TPTVolatile tptVolatile = new TPTVolatile();
tptVolatile.start();
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
e.printStackTrace();
}
tptVolatile.stop();
}
结果
running
第一次被打断
第二次被打断