线程信令序列

时间:2016-08-20 11:55:25

标签: java multithreading

在下面的代码中,我使用wait() - notify()实现了线程间通信,它给了我预期的输出。 预期产出:123456789实际产量:123456789

我的问题是,是否有任何保证始终'主线程'将获得第一次执行的机会,因为线程调度依赖于jvm。如果'子线程'获得第一次机会,notify()信号将错过,主线程'将永远等待。我怎样才能确认主线程'将永远执行。另外请确认以下代码是否可以改进。

package com.test.Thread;

public class ThreadExample1 {

    public static void main(String[] args) throws InterruptedException{

        ThreadChild1 lockingObj = new ThreadChild1();
        lockingObj .start();
        synchronized(lockingObj ){
            for(int i=1;i<10;i++){
                System.out.println("Main "+i);
            }
            lockingObj.wait();
            System.out.println("Main got notified");

        }

    }

}

class ThreadChild1 extends Thread{

    public void run(){
        synchronized(this){
            for(int i=1;i<10;i++){
                System.out.println("Child "+i);
            }
            this.notify();
            }
    }
}

2 个答案:

答案 0 :(得分:3)

您的代码错误是因为您提到了自己:您无法确定哪个线程首先出现。 还有其他可能出错的问题 - wait可以在没有notify的情况下醒来。

您可以在Javadoc for the wait method中阅读相关内容,这也解释了您应该做的事情:

  

在一个参数版本中,中断和虚假唤醒是   可能,这个方法应该总是在循环中使用:

synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }

在你的代码中,你可以用一个表达条件的布尔变量来解决它&#34;我收到了通知&#34;:

public class ThreadExample1 {

    public static void main(String[] args) throws InterruptedException {
        ThreadChild1 lockingObj = new ThreadChild1();
        lockingObj.start();

        synchronized (lockingObj) {
            for(int i = 1; i < 10; i++) {
                System.out.println("Main " + i);
            }
            while (!lockingObj.haveNotified) {
                lockingObj.wait();
            }
            System.out.println("Main got notified");
        }

    }

}

class ThreadChild1 extends Thread{
    private boolean haveNotified;
    public void run(){
        synchronized (this) {
            for (int i = 1; i < 10; i++) {
                System.out.println("Child " + i);
            }
            haveNotified = true;
            this.notify();
        }
    }
}

答案 1 :(得分:1)

虽然这在您的系统上正常工作,但它并不是一种保证,因为您的怀疑可能会在另一个系统上变为现实。线程行为很难/无法预测。因此,我喜欢在最坏的情况下思考,如果我能想出一个可能的突破情况(正如你刚才描述的那样),我只需重新设计以确保它能够正常工作。

测试代码的一个好方法是在关键时刻暂停/暂停线程,方法是在IDE中添加断点,在可能的情况下添加一个非常耗时的任务/调用(不是故障保护),或者通过虚拟暂停线程(并不总是理想的)。此外,我确信有一些库可以扩展这种类型的测试。

我希望这能帮助你朝着正确的方向前进。