线程 notifyAll() [重复]

Posted

技术标签:

【中文标题】线程 notifyAll() [重复]【英文标题】:Threads notifyAll() [duplicate] 【发布时间】:2016-12-02 07:05:37 【问题描述】:

给定一个线程有多种状态:alive runnable running waiting 和终止。 notifyAll() 方法假设将所有正在“等待”对象锁的线程放回“可运行”状态,在该状态下可以选择它作为下一个正在运行的对象。 下面的示例实例化并启动 3 个 Reader 线程,这些线程进入等待(wait() 方法),直到 'calc' 对象的锁被释放。 calc 对象线程被实例化并在此之后启动,它将一些数字相加,然后是 notifyAll()。

我的问题是,为什么 calc 线程不是每次都通知所有 Reader 线程?当我在我的计算机上运行它时,它会被击中并错过。

public class Reader extends Thread
    Calculator c;

    public Reader(Calculator calc)
        c=calc;
    

    public void run()
        synchronized(c)
            try
                System.out.println("Waiting for calculation...");
                c.wait();
            catch(InterruptedException e)
            System.out.println("Total is: "+c.total);
        
    
    public static void main(String[] args)
        Calculator calc = new Calculator();
        new Reader(calc).start();
        new Reader(calc).start();
        new Reader(calc).start();
        new Thread(calc).start();
    

class Calculator implements Runnable
    int total;

    public void run()
        synchronized(this)
            for(int i =0; i<100; i++)
                total+=i;
            
            notifyAll();
        
    

【问题讨论】:

notifyAll() 不会 立即使线程可运行。它有效地将它们的状态从 WAITING 更改为 BLOCKED。线程 A 中的 o.wait() 调用在线程 A 获得对象 o 上的锁之前无法返回,但它不能在线程 B 调用 o.notifyAll() 时这样做,因为线程 B必须持有锁才能进行调用。 请查看Liedman's answer 至Java: notify() vs. notifyAll() all over again。 【参考方案1】:

当执行多个线程时,线程的执行顺序是保证的。

在您的情况下,Calculator 线程很有可能完成它的循环并调用notifyAll(),甚至在任何Reader 线程进入可运行状态之前。所以所有Reader 将继续等待并且永远不会打印total

为避免这种情况,在此特定示例中,您可以在 Calculator 中使用另一个标志 isCalculated,并在计算完成后设置此标志。 Reader 线程也将检查此标志并仅在 isCalculatedfalse 时等待。

class Reader extends Thread 
  Calculator c;

  public Reader(Calculator calc) 
    c = calc;
  

  public void run() 
    synchronized (c) 
      try 
        System.out.println("Waiting for calculation...");

        if (!c.isCalculated)  // wait only if calculation is not done
          c.wait();
        
       catch (InterruptedException e) 
      
      System.out.println("Total is: " + c.total);
    
  


class Calculator implements Runnable 
  int total;
  boolean isCalculated;

  public void run() 
    synchronized (this) 
      for (int i = 0; i < 100; i++) 
        total += i;
      

      isCalculated = true;  // set flag to mark that computation is complete
      notifyAll();
    
  

【讨论】:

更好的是,我本来打算寻求解决这个问题的方法。谢谢。【参考方案2】:

正如@Sudhir 所述,您可以在调用 wait 之前检查一些标志, 查看本教程:http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

在您的情况下,可能会在调用 wait 之前调用 notifyAll() .. 因此线程可能会继续等待调用 notify

【讨论】:

并发是我书中的下一章(sierra k bates b java 7)。这是一本为我的 OCP 做准备的好书。也许我问这个问题是跳了枪,很快就会揭晓。然而,示例代码确实敲响了警钟。

以上是关于线程 notifyAll() [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程_wait/notify/notifyAll方法

java—多线程—notify/notifyAll

线程等待机制——wait/notify(notifyAll)

线程等待机制——wait/notify(notifyAll)

notify()notifyAll()wait()方法

notify()notifyAll()wait()方法