Baeldung 翻译系列之Java并发基础:
Java中的concurrent包
Java中的Synchronized关键字
Future介绍
ThreadLocal介绍
Java线程的生命周期
如何杀掉一个Java线程
Java中的线程池介绍
实现Runnable接口还是继承Thread类
Java中的wait和notify方法
Runnable vs Callable
wait和sleep的区别
Thread.join方法介绍
Java中使用锁对象
ThreadPoolTaskExecutor中的corePoolSize和maxPoolSize
Java中的异步编程
1. 介绍
在这篇简短的文章中,我们将介绍如何在Java中停止一个线程 - 这并不简单,因为Thread.stop()
方法已经被弃用。
如Oracle的这个更新所解释的,stop()
可能会导致监视的对象被破坏。
2. 使用一个标志位
让我们从创建并启动线程的类开始。这个任务不会自行结束,所以我们需要某种方式来停止这个线程。
我们将使用一个原子标志位来实现这一点:
public class ControlSubThread implements Runnable {
private Thread worker;
private final AtomicBoolean running = new AtomicBoolean(false);
private int interval;
public ControlSubThread(int sleepInterval) {
interval = sleepInterval;
}
public void start() {
worker = new Thread(this);
worker.start();
}
public void stop() {
running.set(false);
}
public void run() {
running.set(true);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
System.out.println(
"Thread was interrupted, Failed to complete operation");
}
// do something here
}
}
}
我们使用的是 AtomicBoolean
,而不是让 while
循环评估一个恒定的 true
。现在,我们可以通过将其设置为 true
/false
来开始/停止执行。
如我们在介绍原子变量的文章中所解释的,使用 AtomicBoolean
可以防止从不同的线程设置和检查变量时发生冲突。
3. 中断一个线程
当 sleep()
设置为一个很长的时间,或者我们正在等待一个可能永远不会被释放的锁时,会发生什么?
我们面临的风险是阻塞时间过长或者永远无法干净地终止。
我们可以为这些情况创建 interrupt()
,让我们向类中添加一些方法和一个新的标志:
public class ControlSubThread implements Runnable {
private Thread worker;
private AtomicBoolean running = new AtomicBoolean(false);
private int interval;
// ...
public void interrupt() {
running.set(false);
worker.interrupt();
}
boolean isRunning() {
return running.get();
}
boolean isStopped() {
return stopped.get();
}
public void run() {
running.set(true);
stopped.set(false);
while (running.get()) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
System.out.println(
"Thread was interrupted, Failed to complete operation");
}
// do something
}
stopped.set(true);
}
}
我们添加了一个 interrupt()
方法,它将 running
标志设置为 false
,并调用 worker
线程的 interrupt()
方法。
如果在调用此方法时线程正在睡眠,sleep()
将会因 InterruptedException
退出,任何其他的阻塞调用也会如此。
这将线程返回到循环中,由于 running
是 false
,所以它将退出。
4. 总结
在这个简明教程中,我们研究了如何使用原子变量,可选地结合调用 interrupt()
,来干净地关闭一个线程。这肯定比调用已经被弃用的 stop()
方法并冒着永久锁定和内存损坏的风险要好。
评论区