停止Java线程的安全方法

Nar*_*ode 1 java multithreading

谁能向我解释为什么第一个线程不起作用而第二个线程完美运行:

public class Test {

    public static void main(String args[]) throws InterruptedException {
        TestThread1 t1 = new TestThread1();
        TestThread2 t2 = new TestThread2();

        t1.startThread();
        t2.start();

        Thread.sleep(4000);

        t1.stopThread();
        t2.stopThread();
    }
}

class TestThread1 extends Thread {

    private volatile TestThread1 thread;

    public void startThread() {
        thread = new TestThread1();
        thread.start();
    }

    public void run() {
        while (thread != null) {
            System.out.println("RUNNING 1 ...");
        }
    }

    public void stopThread() {
        thread = null;
    }
}

class TestThread2 extends Thread {

    private volatile boolean finished = false;

    public void run() {
        while (!finished) {
            System.out.println("RUNNING 2 ...");
        }
    }

    public void stopThread() {
        finished = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我在TestThread1class 内部调试时: Inside startThread,thread成员被填充(所以它不是null), inside run,thread成员是null!!! 最后,里面stopThread,thread成员不是null!

谁能向我解释这里发生了什么?

Bru*_*uno 5

在这里,您有两个实例TestThread1 t1:

  • 一个存储在您的t1局部变量中(在您的main方法中)。
  • 一个存储在您的thread实例变量 (of t1) 中。

t1从未开始,t1.thread是。

t1.stopThread()设置t1.thread为null,但不影响t1.thread.thread。

既然你开始了t1.thread,它的run方法是使用t1.thread.thread:

  • 这从未设置为任何内容(因此它使用null)。
  • t1.stopThread()像您一样调用只会设置t1.thread为null,而不会影响t1.thread.thread.

更一般地说,您不能像这样“杀死”一个线程,但您可以在方法中实现测试以告诉它在某些情况下返回。您在第二个测试中所做的更接近于此(使用while (!finished) { ... }volatile 变量)。

我不会将测试限制为finished. 测试线程是否被中断也很有用,特别是因为如果您在一个ExecutorService shutdownNow()will 中运行您的可运行程序,将尝试中断它们(请参阅此问题)。

我会用while (!finished && !Thread.currentThread().isInterrupted()) { ... }.

(注之间的区别Thread.currentThread().isInterrupted()和Thread.interrupted():他们可能看起来相似,但后者也将复位状态,你可能不希望。)

根据循环中的内容(或是否存在循环),您可能希望if (finished || Thread.currentThread().isInterrupted()) { return; }在有意义的各个战略点使用类似的东西。