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

2023-12-07

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()呢?请帮我一下。


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

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

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

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

Update

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

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

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

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

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

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

如果生产者没有等待wait()调用,它必须在方法外部(可能等待进入方法并以这种方式获取锁)。当消费者退出该方法并释放锁时,生产者获取它并检查布尔标志。它被设置为 false,因此生产者不尝试打电话 wait()然后将其值去掉,设置布尔标志并调用notify().

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Wait() 和 Notify() 概念 - Java 多线程 的相关文章

随机推荐

  • 具有多个条件的 COUNTIF

    您能告诉我如何在多个条件下使用 COUNTIF 吗 我的提案 左 显示了一项标准 不同区域 的公式 但是 我有兴趣计算每个不同月份的不同区域 两个标准 右侧 期望的结果 您可以使用COUNTIFS instead 1 COUNTIFS A
  • 为什么无穷大在 Windows 10 控制台中打印为“8”?

    我正在测试除法返回的内容 包括零 即0 1 1 0 and 0 0 为此 我使用了类似于以下内容的内容 Console WriteLine 1d 0d 然而这段代码打印8 not Infinity或其他一些字符串常量 例如PositiveI
  • PropertyGrid - 根据另一个属性值更改下拉属性编辑器的项目

    我正在尝试在自定义组件中实现下拉属性 并且我使用了这个答案 and 这个答案作为指导 到目前为止 我设法让它工作 并在下拉列表中使用预定义的项目 但我仍然需要弄清楚如何更改下拉列表中的项目 这是我到目前为止的代码 从上面提到的链接构建 Ty
  • 静态javascript未在jade中呈现(使用express/node.js)

    我希望你一切都好 我突然无法在 jade 模板中渲染任何外部 javascript 为了弄清楚事情的真相 我将其精简到最低限度 节点0 6 11 Express 2 5 8 jade 0 20 3 app js var express re
  • 协调两个对象集合

    我有一个表单 用户可以在其中使用 DataGrid 修改对象集合 打开表单时 我会创建原始集合的深层副本 如果按下 取消 按钮 我只会丢弃该副本 问题是 当按下 确定 按钮时 我必须协调可能的更改 修改现有对象的属性 新对象添加到集合中的任
  • Log4j JDK 日志适配器:在启动过程后期应用 LogManager 系统属性

    我有一个运行 Web 应用程序的 WebSphere 应用程序服务器 我从 Eclipse 启动服务器 该应用程序中的主要日志记录框架是 log4j2 但也有一些使用 java util logging 的第三方库 我想将这些日志重定向到
  • 实时网络编程:它是如何工作的?

    作为一名 Web 开发人员 我借助 Redis 或 Pusher 等第三方服务开发了聊天服务和其他一些实时协作服务 它们提供了简单的 API 我可以使用发布 订阅模型来实现通过网络服务器的双向通信 我现在想实现一个简单的推送通知 而不使用任
  • 阻止选择下拉列表打开,但允许触发其事件

    有什么方法可以捕获 html select 事件 并阻止 html select 下拉列表打开吗 禁用 html select 被排除 因为事件也将被禁用 我怀疑这实际上会阻止它打开 但它将确保 DropDown 始终保持相同的值
  • 如何根据其中一个成员的值对结构数组进行排序,并根据另一个成员打破联系?

    假设有一个结构 struct x int a b c 结构体数组包含arr 0 4 2 5 arr 1 6 3 1 arr 2 4 1 8 那么我们如何根据成员 a 的值按升序对这个数组进行排序 将根据成员 b 的值打破平局 所以排序后的数
  • ReaderT 设计模式:参数化环境

    我基于以下内容构建了一个项目ReaderT设计模式 我选择使用简单的处理程序注入作为函数参数 而不是使用类型类方法进行依赖项注入 这部分工作得很好 因为我们能够静态构建依赖树并动态定义环境 环境可能包含配置以及日志记录效果 String g
  • 您可以在迭代 std::list 时从其中删除元素吗?

    我的代码如下所示 for std list
  • 是否有 Visual Studio 宏可以在类中每个方法的开头设置断点?

    是否有 Visual Studio 宏 版本 2008 或 2010 可以在类中每个方法的开头设置断点 我已经看到了参考文献的提示 但我无法挖掘出真正的参考文献 名为的 Visual Studio 扩展OzCode确实具有在类的所有成员上设
  • 检测外部进程是否是交互式的并且有任何可见的 UI

    我似乎无法找到一种方法来确定是否Process有一个用户界面 例如一个用户可见的窗口 Environment UserInteractive对于外部进程没有用处 process MainWindowHandle IntPtr Zero在我的
  • 在 swift 中表达具有动态范围的 for 循环

    或者我如何在 for 循环条件中使用索引 嘿人们 由于我们在 swift 3 中没有 c 风格的 for 循环 我似乎找不到一种方法来表达更复杂的 for 循环 所以也许你可以帮助我 如果我写这个 for int i 5 num i gt
  • 面板之间切换

    我有 1 个表单中的 3 个面板来完成输入某些数据的过程 单击面板中的下一个按钮时 应显示下一个面板 最初 我启用了第一个面板的可见性并禁用了其他面板的可见性 当单击下一个按钮时 将执行以下代码 panel1 Visible false p
  • PHP:以五个为一组显示数据库中的条目?

    是否可能 如果可以 我该怎么做 选择数据库表中的所有条目 然后在一组中同时显示五个结果 含义 举个例子 我的数据库中有 15 条记录 那么我想像这样呈现我的数据 div class 1 5 Record 1 Record 2 Record
  • 如何使用 Tensorflow 1.0 Java API 创建/初始化变量

    我正在尝试移植这行Python代码 my var tf Variable 3 name input a 到爪哇 我能够做到这一点tf constant这样 graph opBuilder Const name setAttr dtype t
  • matplotlib轮廓图中的对称对数色阶

    如何创建具有符号对数 对称对数 比例的等高线图 即显示负值和正值的对数刻度 一种可能性是解决这个例子 http matplotlib org examples pylab examples contourf log html 这给出了对数刻
  • 如何停止 SAS 中的“锁不可用于 <数据集>”错误?

    运行 SAS 程序时 我总是收到 锁不可用 错误 如果我在一个程序中多次对同一数据集执行操作 通常会发生这种情况 研究此错误后 我了解到这意味着两个程序正在尝试访问同一数据集 换句话说 这类似于尝试打开其他人或您自己已在使用的文档 这是给我
  • Wait() 和 Notify() 概念 - Java 多线程

    class Q volatile boolean valueSet false volatile int n synchronized int get if valueSet try wait catch InterruptedExcept