如何kill正在运行的java线程
一般我们把需要较长时间处理的任务放在线程中处理,为更好的用户体验,正在运行的任务最好能取消,如用户误操作(重复导入大量数据)。本文介绍如何暂停java 线程————不是简单使用Thread.stop方法,已标记为不建议使用,详细解释请参考官方文档。
使用标志位
首先我们创建一个类,其负责创建和启动线程。因为线程任务不能自己结束,所以定义结束线程的方式,这里我们使用原子类型标志(atomic):
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
}
}
}
代替使用常量true进行while循环,我们使用AtomicBoolean作为while条件,现在我们可以通过设置该条件true/false实现启动或停止线程。AtomicBoolean可以保障不同线程之间同步。
使用interrupt方法中断线程
在上面实现方式中,如果遇到sleep被设置为很长时间,或等待锁永远不释放,则线程一直被阻止或线程永远不终止(一致在while循环体内)。
我们可以使用interrupt方法解决这中场景,在上面示例的基础上增加几个方法和新的标志位:
public class ControlSubThread implements Runnable {
private Thread worker;
private int interval = 100;
private AtomicBoolean running = new AtomicBoolean(false);
private AtomicBoolean stopped = new AtomicBoolean(true);
public ControlSubThread(int sleepInterval) {
interval = sleepInterval;
}
public void start() {
worker = new Thread(this);
worker.start();
}
public void stop() {
running.set(false);
}
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的线程调用该方法,sleep方法会结束并抛出InterruptedException异常,与其他的阻塞调用一样。然后回到循环内,因为running为false,任务会结束。
总结
本文我们通过使用atomic变量,并整合线程的interrupt()方法,干净利落地停止了正在运行的线程。这显然比调用已弃用的stop()方法、冒永久锁定和内存崩溃的风险要好。