1

我正在学习 Java 中的线程,并且我有以下程序。ThreadA 中的 while threadA 条件检查似乎并不像我预期的那样频繁。我在控制台窗口中看到的唯一 println 语句包含大于 100 的 i 变量。似乎它正在等待并慢慢打印到控制台。我会想象这将在一秒钟左右完成。我显然在这里误解了一些东西,关于为什么 ThreadTester 不打印 100 次的任何想法?

public class ThreadTester {
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.start();
    }
}

public class ThreadA extends Thread{
    private volatile Thread threadA = Thread.currentThread();

    public void run() {
        while(threadA == Thread.currentThread()){
            for(int i=0; i<100; i++){
                System.out.println("ThreadA " + i);
            }
        }
    }

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

示例输出:

ThreadA 120
ThreadA 121
ThreadA 122
ThreadA 123
ThreadA 124
ThreadA 125
ThreadA 126
ThreadA 127
ThreadA 128
ThreadA 129
ThreadA 130
ThreadA 131
ThreadA 132
ThreadA 133
ThreadA 134
ThreadA 135
ThreadA 136

如何杀死线程

类 Thread 有一个方法 stop(),它应该知道如何杀死当前线程。但它在多年前就被弃用了,因为它可能会使程序中的某些对象因对象实例的不正确锁定和解锁而导致不一致的状态。

杀死线程有不同的方法。其中之一涉及在线程上创建自己的方法,例如 stopMe(),在其中您将自己的布尔变量,例如 stopMe,设置为 false,并在线程的方法 run() 内定期测试其值。如果应用程序代码将 stopMe 的值设置为 true,则只需在方法 run() 中退出代码执行即可。在示例 20-10 中,方法 run 中的循环检查变量 stopMe 的值,该变量使用对当前 Thread 对象的引用进行初始化。一旦更改(在这种情况下设置为 null),处理将完成。

变量 stopMe 已使用 volatile 关键字声明,它警告 Java 编译器另一个线程可以修改它,并且此变量不应缓存在寄存器中,因此所有线程必须始终看到它的新值。

预订有关如何构造线程的示例代码,以便您可以在需要时将其杀死:

 class KillTheThread{
               public static void main(String args[]){
               Portfolio4 p = new Portfolio4("Portfolio data");
             p.start();

             // Some other code goes here,
             // and now it's time to kill the thread
             p.stopMe();

               }
    }
class Portfolio4 extends Thread{

private volatile Thread stopMe = Thread.currentThread();

    public void stopMe() {
        stopMe = null;
    }

    public void run() {
        while (stopMe == Thread.currentThread()) {
          try{
            //Do some portfolio processing here
          }catch(InterruptedException e ){
            System.out.println(Thread.currentThread().getName()
                                        + e.toString());
        }

     }
 }
4

2 回答 2

3

在对象成为当前线程之前,该threadA字段由主线程初始化,因此其值被设置为主线程。ThreadA当循环运行时,ThreadA是当前线程,因此不会发生迭代。重新启动 Eclipse 之前得到的奇怪输出可能是由于 Eclipse 运行了您的代码的先前版本。

于 2013-07-06T23:31:27.350 回答
1

1.
这只有在 ThreadA 是主线程时才有效。

2.
stopMe() 有一个非常简单的方法。

private volatile boolean stopped = false;
public void stopMe() {
    stopped = true;
}
public void run() {
    while (!stopped) {
        // ...
    }
}

3.
关于“如何杀死一个线程”。您可以使用Thread.interrupt().
实际上,FutureTask.cancel()用于Thread.interrupt()停止工作线程。

但是,调用 interrupt() 实际上只是向线程发送信号。线程必须做一些额外的工作来响应信号。它不会自行停止。

最后你需要检查InterruptedExceptionand Thread.isInterrupted(),这与 . 基本相同stopMe()

于 2013-07-07T04:15:26.647 回答