3
class Q {
  volatile boolean valueSet = false;
  volatile int n;

  synchronized int get () {
    if ( !valueSet ) {
      try {
        wait();
      } catch ( InterruptedException e ) {
        System.out.println( "InterruptedException caught" );
      }
    }

    System.out.println( "Got: " + n );
    valueSet = false;
    notify();
    return n;
  }

  synchronized void put ( int n ) {
    if ( valueSet ) {
      try {
        wait();
      } catch ( InterruptedException e ) {
        System.out.println( "InterruptedException caught" );
      }
    }

    this.n = n;
    valueSet = true;
    System.out.println( "Put: " + n );
    notify();
  }
}

class Producer
    implements Runnable {
  Q q;
  Producer ( Q q ) {
    this.q = q;
    new Thread( this, "Producer" ).start();
  }

  public void run () {
    int i = 0;
    while ( true ) {
      q.put( i++ );
    }
  }

}

class Consumer
    implements Runnable {
  Q q;
  Consumer ( Q q ) {
    this.q = q;
    new Thread( this, "Consumer" ).start();
  }

  public void run () {
    while ( true ) {
      q.get();
    }
  }

}

class PCFixed {
  public static void main ( String args[] ) {
    Q q = new Q();
    new Producer( q );
    new Consumer( q );
    System.out.println( "Press Control-C to stop." );
  }
}

我无法理解这是如何工作的。以这个流程为例。Producer进入put方法,调用notify()。如果消费者还没有调用 wait() 怎么办?还有,一旦producer调用notify(),在producer还没有放开monitor的情况下,consumer怎么进入get()方法呢?请帮帮我。

4

3 回答 3

2

我假设顶部的类是 Q,它缺少一些代码。无论如何,总体思路是布尔值valueSetwait()/notify()调用协同工作。

如果消费者已经开始等待,他已经通过同步get()方法获得了Q实例的锁,然后在等待的时候释放它。

如果消费者还没有开始等待,生产者可能拥有 Q 实例的锁,因为该put()方法在同一个锁上同步。一旦生产者退出锁,他将调用notify() 并将 valueSet boolean 设置为 true

消费者的下一次调用将在尝试等待之前get()读取布尔值,注意那里有东西,获取内容并做任何需要的工作。如果没有设置值,这意味着在消费者不在的情况下没有任何东西进来,他会锁上新工作的锁,下一个会叫醒他。nwait()notify()

更新

在评论中的场景中,您本质上是在询问完全相同的情况,但情况相反。同样的逻辑也适用。

消费者当前正在等待,生产者调用notify()。生产者当前拥有锁,并将在方法执行期间继续持有锁。所做notify()的只是让另一个正在等待锁的线程知道,当锁被释放时,它可以尝试获取锁并恢复执行。在这种情况下,只有一个其他线程,但如果有多个线程,那么它将只选择一个(唤醒每个人,notifyAll()应该被调用)。

  1. 生产者退出方法,释放锁。
  2. 消费者醒来并获得锁。

此时,生产者是否已经出现并且当前正在等待锁定,或者它是否还没有进入方法是模棱两可的。wait()布尔标志和/的相同串联也notify()适用于此。

在消费者通过退出方法释放锁之前,它会将布尔标志设置为 false 并调用notify()

如果生产者当前已经在等待锁,调用notify()将让它知道它可以在锁被释放时唤醒并继续。

如果生产者没有通过wait()调用等待,它必须在方法之外(可能等待进入方法并以这种方式获取锁)。当消费者退出方法并释放锁时,生产者获取它并检查布尔标志。它已设置为 false,因此生产者不会尝试调用 wait(),只是将其值关闭,设置布尔标志并调用notify().

于 2011-12-20T18:26:00.940 回答
1
  1. 如果消费者还没有调用 wait() 怎么办?
    • 消息将丢失
  2. 一旦生产者调用了notify(),在生产者还没有放开监听器的情况下,消费者怎么进入get()方法呢?
    • 它会死锁 - 阻塞直到监视器被释放。
于 2011-12-20T18:12:13.187 回答
0

我将尝试了解这是如何工作的。例如,Producer进入put()方法,看到监视器空闲,他可以执行推杆动作。在他在这里做他的工作的时候,他Consumer试图执行这个get()动作。但是他失败了,因为监视器已经被 s 占用了Producer,所以他调用wait()意味着他被阻塞在该行代码处,等待其他线程调用notify()get()这里的诀窍是,在他被通知监视器再次空闲之前,他再也不会打电话了,这意味着他不会再执行任何空周期。所以,当Producer他完成他的工作时,他打电话notify()Consumer从他离开的地方继续。我知道一开始有点难以理解,也有点难以解释,但是当你这样做时,你会发现这些都是非常简单而强大的东西。祝你好运!

于 2011-12-20T18:19:33.473 回答