【问题标题】:Does a thread implicitly call notifyAll() , if other Threads are waiting on it?如果其他线程正在等待,线程是否会隐式调用 notifyAll() ?
【发布时间】:2014-04-21 20:13:32
【问题描述】:

我想我应该说的第一件事是我不是在寻找解决方案,这是 hwk,但它运行正确,对我有很大帮助的是澄清..

我们刚刚在我的面向对象编程课程中介绍了线程,并收到了我完成的作业。在我的代码中,我从不调用 notifyAll() ,但它似乎在退出 run() 之前被隐式调用。我的另一个同学也有同样的问题。我在某处读到,当它正在等待的线程死亡/退出运行方法时,通知正在等待另一个线程的线程(隐式 notifyAll() ?)。这是我的代码(可运行的,以及所有运行的主要代码)

如果我删除等待,并将 InterruptedException 替换为 Throwable ,代码会运行,但不正确,线程会在它们的睡眠时间之后出现,然后打印终止消息并按照它们出现的顺序死亡。

我无法发布图片,所以我会尽力描述它的工作原理: 每个线程在分配的时间内休眠并保存一个 Thread 数组,该数组保存对它必须等待的线程的引用

例如:T1 到达 2 秒取决于 T2,T3 T2 4秒到达 无人问津 T3 6秒到达 无人问津 所以... T1到达,必须等待T2和T3才能终止,T2和T3可以立即终止..

这里是到达时间和他们依赖的人:

T1 4 秒,无人 T2 6 秒,无人 T3 7 秒,无人 T4 2 秒, T1,T2 T5 3 秒, T3 T6 1 秒,T3,T4 T7 8 秒, T4 T8 5 秒,T6

抱歉,解释太长了,我不是在寻找解决方案,代码运行正常,我需要澄清一下如何调用 wait 并且从不调用 notify 它是如何运行的?

public class TScheduler {




    public static void main(String[] args) {




    long originTime = System.currentTimeMillis();

    // Long.parse.long(args[0]) * 1000
    DepThread t1 = new DepThread(originTime , 4000 , new Thread[]{});
    Thread T1 = new Thread(t1);
    T1.setName("T1");
    // Long.parse.long(args[1]) * 1000
    DepThread t2 = new DepThread(originTime , 6000 , new Thread[]{});
    Thread T2 = new Thread(t2);
    T2.setName("T2");

    DepThread t3 = new DepThread(originTime , 7000 , new Thread[]{});
    Thread T3 = new Thread(t3);
    T3.setName("T3");

    DepThread t4 = new DepThread(originTime , 2000 , new Thread[]{T1,T2});
    Thread T4 = new Thread(t4);
    T4.setName("T4");

    DepThread t5 = new DepThread(originTime , 3000 , new Thread[]{T3});
    Thread T5 = new Thread(t5);
    T5.setName("T5");

    DepThread t6 = new DepThread(originTime , 1000 , new Thread[]{T3,T4});
    Thread T6 = new Thread(t6);
    T6.setName("T6");

    DepThread t7 = new DepThread(originTime , 8000 , new Thread[]{T4});
    Thread T7 = new Thread(t7);
    T7.setName("T7");

    DepThread t8 = new DepThread(originTime ,5000 , new Thread[]{T6});
    Thread T8 = new Thread(t8);
    T8.setName("T8");

    DepThread t9 = new DepThread(originTime , 500 , new Thread[]{T7});
    Thread T9 = new Thread(t9);
    T9.setName("T9");




    T1.start();
    T2.start();
    T3.start();
    T4.start();
    T5.start();
    T6.start();
    T7.start();
    T8.start();
    T9.start();






    }

}




public class DepThread implements Runnable {

    long sleepTime;
    Thread[] depThrdArray;
    public boolean done = false ;
    long baseTime ;

    public DepThread( long baseTime , long arrivalTime ,  Thread[] depThrdArray ){
    //super();
    this.baseTime = baseTime;
    this.sleepTime = arrivalTime;
    this.depThrdArray = depThrdArray;
    this.done = false;
    }

    @Override
    public void run() { 
    try {
        Thread.sleep(sleepTime);
        System.out.println( Thread.currentThread().getName() + " arrived at " + (System.currentTimeMillis() - baseTime));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    for ( int i = 0 ; i < depThrdArray.length ; i ++){
        if ( depThrdArray[i].isAlive()){
        synchronized(depThrdArray[i]){
            try {
            depThrdArray[i].wait();
            System.out.println(Thread.currentThread().getName() + " waiting on " + depThrdArray[i].getName() 
                + " time " + (System.currentTimeMillis() - this.baseTime));
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        }

    }

    this.done = true;
    //synchronized (this){
    //    notifyAll();
    //}
    System.out.println(Thread.currentThread().getName() + "  at time " + ( System.currentTimeMillis() -  baseTime) + " terminating");
    }

}

【问题讨论】:

标签: java multithreading notify


【解决方案1】:

线程在终止时调用notifyAll 以支持join 功能。这在 Thread#join 的 Javadoc 中有记录:

此实现使用以this.isAlive 为条件的this.wait 调用循环。当线程终止时,this.notifyAll 方法被调用。建议应用程序不要在Thread 实例上使用waitnotifynotifyAll

那么基本上有两个结论:

  • 如果您想等到线程终止,请使用join
  • 如果你想使用wait,否则不要使用线程实例作为监视器。

【讨论】:

  • 我读到和上面这位先生一样的东西,我认为它可能只与 join() 有关,当我问我的教授时,他几乎不理我,说他从来没有听说过其中。我已经运行了我发布的代码,它按照分配运行,如果我删除 depThrdArray[i].wait() 并将 InterruptedException 更改为 Throwable ,代码无法正确运行,所以,让我相信等待被执行..
  • notifyAll 被调用,我想你的教授没有阅读文档。如果您还有其他不确定性,请使用more minimal example 编辑问题,清楚地说明它。
  • 注意(如前所述)这取决于实现。另一个 JVM 可能不会使用 notifyAll(),因此它当然应该被视为 hack @user3395349。对于另一个数据点,Java 6 没有提到这一点,尽管这就是幕后发生的事情:docs.oracle.com/javase/6/docs/api/java/lang/…
  • 我是线程的新手,等待另一个线程与对象不是一个好习惯吗?对于大多数生产者-消费者示例,我看到有 2 个不同的扩展线程类调用 getSomething 或 placeSomething 方法,这些方法在同步线程的第 3 个类中实现
  • 如果我在包含 notifyall() 的代码末尾取消注释同步块,是否会消除任何潜在问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
相关资源
最近更新 更多