如何kill正在运行的java线程

如何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()方法、冒永久锁定和内存崩溃的风险要好。

你可能感兴趣的:(如何kill正在运行的java线程)