在Java中杀死一个线程的不同方法

170 阅读3分钟

在Java中没有正式的方法来杀死一个线程。停止一个线程完全由JVM管理。尽管Java提供了几种管理线程生命周期的方法,如start()sleep()stop()(在Java 1 .1中被废弃 )等,但没有提供任何方法来杀死一个线程并干净地释放资源。

甲骨文公司指出,废弃stop()方法的原因是它本身就不安全。停止一个线程会导致它解锁所有锁定的监视器。

1.杀死一个线程的两种方法

有效地,我们只能向线程发出信号,让它停止自己,让线程清理资源并终止自己。在Java中,我们可以通过两种方式向线程发送信号。

  • 通过周期性地检查一个布尔标志
  • 通过使用Thread.interrupt()方法来中断线程

让我们了解一下这两种方法。

2.通过检查一个标志

在这个方法中,我们定期检查一个布尔标志,或者在任务的每一步之后。最初,该标志被设置为false。要停止线程,就把标志设为*"真*"。在线程内部,当代码将标志的值检查为真时,它会优雅地销毁自己并返回。

请注意,在这种设计中,一般来说,有两个线程。一个线程将标志值设置为,另一个线程检查标志值。为了确保两个线程一直看到相同的值,我们必须让标志变量 挥发性.或者我们可以使用AtomicBoolean类,它支持对底层易失性 布尔变量进行原子操作。

public class CustomTask implements Runnable {

  private volatile boolean flag = false;
  private Thread worker;

  public void start() {
    worker = new Thread(this);
    worker.start();
  }

  public void stop() {
    flag = true;
  }

  @Override
  public void run() {
    while (!flag) {
      try {
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + " Running...");
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        System.out.println("Thread was interrupted," + e.getMessage());
      }
    }
    System.out.println(Thread.currentThread().getName() + " Stopped");
    return;
  }
}

让我们通过创建两个线程并停止它们来测试这个设计。

CustomTask task1 = new CustomTask();
CustomTask task2 = new CustomTask();

task1.start();
task2.start();

try {
  Thread.sleep(1000);

  task1.stop();
  task2.stop();
} catch (InterruptedException e) {
  System.out.println("Caught:" + e);
}
Thread-0 Running...
Thread-1 Running...
Thread-1 Running...
Thread-0 Running...

Thread-1 Stopped
Thread-0 Stopped

3.通过中断线程

这个方法也与之前使用标志的方法非常相似。唯一的区别是,我们将中断线程,而不是将标志设置为false

所以在线程内部,我们将不断检查线程的中断状态,当线程被中断时,我们将优雅地停止线程。为了检查被中断的线程的状态,我们可以使用 Thread.isInterrupted()方法。它根据线程的中断状态返回

public class CustomTaskV2 implements Runnable {
  private Thread worker;

  public void start() {
    worker = new Thread(this);
    worker.start();
  }

  public void interrupt() {
    worker.interrupt();
  }

  @Override
  public void run() {
    while (!Thread.currentThread().isInterrupted()) {
      try {
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + " Running...");
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        System.out.println("Thread was interrupted with reason : " + e.getMessage());
      }
    }
    System.out.println(Thread.currentThread().getName() + " Stopped");
    return;
  }
}

有趣的是,测试这一设计的代码与之前的设计类似。只有对thread.interrupt()的方法调用是额外的。

CustomTaskV2 task1 = new CustomTaskV2();
CustomTaskV2 task2 = new CustomTaskV2();

task1.start();
task2.start();

try {
  Thread.sleep(1100);isInterrupted
  task1.interrupt();
  task2.interrupt();
} catch (InterruptedException e) {
  System.out.println("Caught:" + e);
}
Thread-0 Running...
Thread-1 Running...
Thread-1 Running...
Thread-0 Running...
Thread was interrupted with reason : sleep interrupted
Thread was interrupted with reason : sleep interrupted
Thread-0 Stopped
Thread-1 Stopped

4.总结

本教程教会了我们使用自定义的解决方案来杀死Java中正在运行的线程。尽管布尔标志的解决方案非常好,但对于线程大部分时间都在等待的长时间运行的任务来说,它可能无法得到理想的结果。

发送一个中断是一个更好的方法来停止一个长期等待的线程。