本文介绍了停止Java线程的安全方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以向我解释为什么第一个线程不起作用而第二个线程完美地工作:

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;
    }
}

当我在TestThread1类内部调试时:在startThread内部,thread成员已填充(因此不是null),在run内部,thread成员是null!最后,在stopThread内部,thread成员不是null !!!

有人可以向我解释这里发生了什么吗?

解决方案

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

  • 其中一个存储在您的t1局部变量中(在您的main方法中).
  • 其中一个存储在您的thread实例变量(为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) { ... }与易失性变量一起使用).

我不会将测试限制为finished.测试线程是否被中断也很有用,特别是因为如果您在ExecutorService shutdownNow()中运行可运行对象,则会尝试中断它们(请参阅).

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

(请注意Thread.currentThread().isInterrupted()Thread.interrupted()之间的区别:它们看起来似乎很相似,但是后者也会重置状态,这可能是您不想要的.)

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

Can anyone explain to me why the first thread doesn't work and the second works perfectly:

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;
    }
}

When I debug inside TestThread1 class: Inside startThread, the thread member is filled (so it is not null), inside run, thread member is null!!! And finally, inside stopThread, the thread member is not null!!!

Can anyone explain to me what is happening here?

解决方案

Here, you have two instances of TestThread1 t1:

  • One is stored into your t1 local variable (in your main method).
  • One is stored into your thread instance variable (of t1).

t1 is never started, t1.thread is.

t1.stopThread() sets t1.thread to null, but it doesn't affect t1.thread.thread.

Since you're starting t1.thread, its run method is using t1.thread.thread:

  • This is never set to anything (so it's using null).
  • Calling t1.stopThread() like you do would only set t1.thread to null, which wouldn't affect t1.thread.thread.

More generally, you can't just "kill" a thread as such, but you can implement tests within the method to tell it to return under certain circumstances. What you've done with your second test is closer to this (using while (!finished) { ... } with a volatile variable).

I wouldn't limit the test to finished. It's also useful to test whether the thread was interrupted, in particular because if you run your runnables within an ExecutorService shutdownNow() will try to interrupt them (see this question).

I'd use while (!finished && !Thread.currentThread().isInterrupted()) { ... }.

(Note the difference between Thread.currentThread().isInterrupted() and Thread.interrupted(): they may seem similar, but the latter will also reset the status, which you might not want.)

Depending on what's within your loop (or whether there is a loop at all), you may want to use something like if (finished || Thread.currentThread().isInterrupted()) { return; } at various strategic points, where it makes sense.

这篇关于停止Java线程的安全方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 16:47