Wait() 和 Notify() 概念 - Java 多线程

发布于 2024-12-22 07:10:58 字数 1448 浏览 3 评论 0原文

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() 怎么办?还有,一旦生产者调用了notify(),在生产者还没有释放monitor的情况下,消费者如何进入方法get()呢?请帮我一下。

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." );
  }
}

I'm unable to understand how this works. Take this flow for instance. Producer enters put method and calls notify(). What if wait() has not been called by the consumer yet? Also, once the producer calls notify(), how can the consumer enter the method get() when the producer has not let go of the monitor yet? Please help me out here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雨落□心尘 2024-12-29 07:10:58

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

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

如果消费者尚未开始等待,则生产者可能拥有 Q 实例的锁,因为 put() 方法在同一锁上同步。一旦生产者退出锁定,他将调用 notify() 并将 valueSet 布尔值设置为 true

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

更新

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

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

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

此时,生产者是否已经恢复并当前正在等待锁,或者是否尚未进入该方法,这是不明确的。布尔标志和 wait()/notify() 的串联也适用于此。

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

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

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

I'm assuming that the class at the top is Q, it's missing some code. Anyway, the general idea is that the boolean valueSet and the wait()/notify() calls work in tandem.

If the consumer has already begun to wait, he has acquired the lock to the Q instance through the synchronized get() method and then releases it while he waits.

If the consumer has not begun to wait yet, the producer may have the lock to the Q instance because the put() method is synchronized on that same lock. Once the producer exits the lock, he will have called notify() as well as set the valueSet boolean to true.

The consumer's next call to get() will read the boolean value before attempting to wait, notice that something's there, take the contents of n and do whatever work is needed. If the value had not been set, meaning that nothing had come in in the consumer's absence, he would wait() on the lock for new work and the next notify() will wake him up.

Update

In your scenario in the comments, you're essentially asking about the exact same situation but in reverse. The same logic applies.

The consumer is currently waiting and the producer calls notify(). The producer currently has the lock and will continue to hold the lock for the duration of the method. All notify() does is let one other thread currently waiting on the lock know that, when the lock is released, it can try to take the lock and resume execution. In this case, there is only one other thread, but if there were multiple threads then it would select only one (to wake everyone, notifyAll() should be called).

  1. The producer exits the method, releasing the lock.
  2. The consumer wakes up and takes the lock.

At this point, it's ambiguous as to whether the producer has already come around and is currently waiting on the lock or if it has not entered the method yet. The same tandem of the boolean flag and wait()/notify() applies to this as well.

Before the consumer releases the lock by exiting the method, it will both set the boolean flag to false and call notify().

If the producer is currently already waiting on the lock, calling notify() will let it know that it can wake up and continue when the lock is released.

If the producer is not waiting through a wait() call, it must be outside the method (possibly waiting to enter the method and acquire the lock that way). When the consumer exits the method and releases the lock, the producer acquires it and checks the boolean flag. It's been set to false, therefore the producer does not attempt to call wait() and just drops its value off, sets the boolean flag and calls notify().

喜爱皱眉﹌ 2024-12-29 07:10:58
  1. 如果消费者还没有调用 wait() 怎么办?
    • 消息将会丢失
  2. 一旦生产者调用了notify(),那么在生产者还没有释放monitor的情况下,消费者如何进入方法get()呢?
    • 它将死锁 - 阻塞,直到监视器被释放。
  1. What if wait() has not been called by the consumer yet?
    • The message will be lost
  2. Once the producer calls notify(), how can the consumer enter the method get() when the producer has not let go of the monitor yet?
    • It will deadlock - block until it the monitor is realeased.
Smile简单爱 2024-12-29 07:10:58

我会尝试了解这是如何工作的。例如,Producer 进入了 put() 方法,看到监视器空闲了,他可以执行 put 动作。当他在这里完成工作时,Consumer 出现并尝试执行 get() 操作。但他失败了,因为监视器已经被 Producer 占用,所以他调用了 wait() ,这意味着他被阻塞在该行代码中,等待其他线程调用<代码>notify()。这里的技巧是,在他被通知监视器再次空闲之前,他再也不会调用 get() ,这意味着他不会再执行任何空循环。因此,当生产者完成工作后,他会调用notify(),而消费者则从上次中断的地方继续。我知道一开始有点难以理解,也有点难以解释,但是当你这样做时,你会发现这些都是非常简单而强大的东西。祝你好运!

I'll try to understand how this works. For example, the Producer has entered the put() method and saw that the monitor is free and he can execute the putting action. At the time he's doing his job here comes the Consumer and tries to execute the get() action. But he fails since the monitor is already taken by the Producer, so he calls wait() meaning he is blocked at that line of code waiting for some other thread to call notify(). The trick here is that he never again calls get() before he's been notified that the monitor is free again, means he won't execute any more empty cycles. So, when the Producer has finished his work, he calls notify() and the Consumer resumes where he left off. I know it's a bit hard to understand at first and a bit hard to explain too, but when you do you'll see that these are really simple and powerful things. Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文