怎么关闭一个 Java 线程 ( Thread ) ? 噢,不,正确的问题是怎么正确的关闭一个 Java 线程?
这个问题是不是很简单? 很简单啊,不就是使用 Thread.stop()
方法么?
但是,根据 ORACLE 的更新文档 ,Thread.stop()
方法可能导致监视器对象被破坏。
因此,我们必须使用其它更安全的方法,或在 Thread.stop()
方法上做一些改变。
使用一个标志 ( Flag )
假设存在一个任务,这个任务并不会自己自动结束,因此我们必须找到一些方式来停止该线程。
为了方便你的理解,我们从创建和启动线程的类开始,一步一步讲解。
首先,我们需要一个原子性的标志 ( flag )
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 来启动/停止执行。
中断线程
当把 sleep()
设置为较长的间隔时,或者我们正在等待可能永远不会被释放的 锁 时会发生什么 ?
我们面临长期阻塞或永不干净的风险。
为了解决这类问题,我们可以创建一个 interrupt()
。
为了演示如何创建 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);
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
}
}
}
上面这段代码中,我们添加了一个 interrupt()
方法,并在该方法中将运行标志设置为 false
,然后调用工作线程的 interrupt()
方法中断线程。
如果线程在调用此函数时处于休眠状态,则 sleep()
会退出并抛出一个 InterruptedException
异常,就像任何其它阻塞调用一样。
后记
哎,本来可以使用 Thread.stop()
解决的问题,结果为了考虑锁和监视器,整蛊了一个长的解决方案,这难道就是 Java 开发不能避免的?
最新评论
Spring Cloud Alibaba 微服务架构实战 https://pan.baidu.com/s/1jF5voFRoeF0lYAzAPBWSbw?pwd=chqk
命令: nload
真是个良心站点哇,大公无私,爱了爱了
还可以直接搞一张映射表,存 uid | time | source_index, 第一次直接查对应的 time 选出前100, 第二次直接用 CompleteFuture 去分别用 source_in
干得漂亮,多个朋友堵条路
2021.2.2版本的不适用吧
现在还可以用么
激活码有用,感谢分享