目录
终止线程的方法
打断sleep函数
打断正常执行的线程
两阶段终止模式
错误的方法
使用线程对象的 stop() 方法停止线程
使用 System.exit(int) 方法停止线程
正确的方法:使用 interrrupt
终止线程的方法
XXXThread.interrupt();
在线程的 run函数中对该线程的中断标记进行判断,自行决定是否终止当前线程。
以及在终止线程之前做一些工作。
interrupt 这个方法并没有强制性地去中断线程任务,只是发送了一个信号给到线程自身,然后让线程自身去决定如何执行。
正因为 interrupt 的灵活性会比较高,所以在 JDK 的线程池中,关于关闭部分的实现也是采用了 interrupt 去实现。
打断sleep函数
public class InterruptThread2 {
static class TestInterruptedStop implements Runnable {
@Override
public void run() {
synchronized (this) {
//如果当前线程被中断,这里需要主动退出
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);// sleep 被打断 抛出异常InterruptedException
// 之后打断标记被清空
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("sleep遇到了中断,程序即将终止");
System.out.println("终止前的相关操作...");
}
System.out.println("running " + (i+1));
}
System.out.println("end");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread testInterruptedStop = new Thread(new TestInterruptedStop());
testInterruptedStop.start();
Thread.sleep(2000);
testInterruptedStop.interrupt();
Thread.sleep(1000);
System.out.println("testInterruptedStop is interrupted:" + testInterruptedStop.isInterrupted());
}
}
打断正常执行的线程
public class InterruptThread3 {
static class TestInterruptedStop implements Runnable {
@Override
public void run() {
synchronized (this) {
int i = 1;
while(!Thread.currentThread().isInterrupted()){
System.out.println("running " + (i++));
}
if(Thread.currentThread().isInterrupted()){// 如果当前线程是打断状态
System.out.println("遇到了中断,程序即将终止");
System.out.println("执行终止前的相关操作...");
}
System.out.println("end");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread testInterruptedStop = new Thread(new TestInterruptedStop());
testInterruptedStop.start();
Thread.sleep(2000);
testInterruptedStop.interrupt();
Thread.sleep(1000);
System.out.println("testInterruptedStop is interrupted:" + testInterruptedStop.isInterrupted());
}
}
两阶段终止模式
在一个线程
T1
中如何
“
优雅
”
终止线程
T2
?这里的【优雅】指的是给
T2
一个料理后事的机会。
错误的方法
使用线程对象的 stop() 方法停止线程
stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
使用 System.exit(int) 方法停止线程
目的仅是停止一个线程,但这种做法会让整个程序都停止
正确的方法:使用 interrrupt
如果被打断线程正处于 sleep、wait、join这三种状态,则会导致被打断的线程抛出 InterruptedException,并清除打断标记,也就是置为 false。
@Slf4j(topic = "c.TestTwoPhaseTermination")
public class TestTwoPhaseTermination {
public static void main(String[] args) throws InterruptedException {
TPTInterrupt t = new TPTInterrupt();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();
}
}
@Slf4j(topic = "c.TPTInterrupt")
class TPTInterrupt {
private Thread thread;
public void start(){
thread = new Thread(() -> {
while(true) {
Thread current = Thread.currentThread();
if(current.isInterrupted()) {
log.debug("料理后事");
break;
}
try {
Thread.sleep(1000);
log.debug("将结果保存");
} catch (InterruptedException e) {
current.interrupt();// 打断标记被清空,需要重新打断设置打断标记为 true
}
}
},"监控线程");
thread.start();
}
public void stop() {
thread.interrupt();
}
}
sleep 的睡眠被打断会抛出异常,情况打断标记,因此在 catch 块中,需要重新设置打断标记。