停止线程的正确姿势
转载
推荐:Java并发编程汇总
停止线程的正确姿势
原文地址
Java线程状态和关闭线程的正确姿势
正文
线程的run()方法正常执行完毕之后线程就正常死亡进入TERMINATED状态了,那么如果我们有中途停止线程的需求,我们应该如何正确的结束一个线程呢?
使用interrupt()方法
在线程内部,其定义了一个变量来标识当前线程是否处于被打断状态,调用interrupt()方法则使这个状态变为true;换句话说,线程在阻塞状态的时候会检查标识状态,如果是true,则抛出InterruptedException,否则阻塞,所以不会打断非阻塞的线程,即对正在运行的线程此方法无效。我们采用这个方法加异常处理的方式来结束一个线程。
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
// 这里的return是必须的,原因后面说明
return;
}
System.err.println("thread interrupt test...");
});
thread.start();
thread.interrupt();
System.out.println("main thread end...");
}
这里关于线程中的打断标识变量(之后以interrupt称)需要说明的是,在特定的情况下其状态会被重置。
- 线程内部在catch了异常之后interrupt的状态会被重置为false。
- 线程调用了Thread.interrupted()方法之后,interrupt的状态会被重置为false。如果需要判断线程是否中断的话可以使用对象方法isInterrupted(),此方法不会重置。
所以在刚才的代码中需要加入return来结束线程,否则的话线程还是会继续往下执行,如下图:
使用isInterrupted()实现:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
int k = 0;
while (k++ < 10) {
System.out.println("do something..." + k);
}
}
System.err.println("thread end...");
});
thread.start();
Thread.sleep(1);
// 主线程流程执行完了,需要停止线程
thread.interrupt();
}
stop()方法——不正确的线程中断方法
在线程提供的方法中还有一个方法可以强制关闭线程——stop()。这个方法可以说是相当的霸道,给人一种“我不管,我就是要你现在立刻死亡(指线程)”的感觉,并且其还会释放线程所有的锁资源,这样可能会导致出现数据不一致从而出现线程不安全的情况,如下面例子。
public class Test {
public static volatile boolean flag = false;
public int state = 0;
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread thread = new Thread(() -> {
synchronized (test) {
try {
test.state = 1;
Thread.sleep(100);
if (flag) {
test.state = 2;
}
System.err.println("thread execute finished...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
Thread.sleep(1);
thread.stop();
flag = true;
System.out.println("state状态:" + test.state);
}
}
在这段代码中,进入线程时默认将state赋为1,接着过一段时间后如果触发了特定条件则把state赋为2,但是在特定条件触发之前,线程就被终止掉了,这个特定条件虽然符合但却没办法执行,从而导致数据的不一致。
结果图:
所以,我们应该采用上面正确的方式而不是stop()来中止线程。此外,stop()方法若在线程start()之前执行,那么在线程启动的时候就会立即死亡。