同步实现:Java

2023-12-25

这是一个消费者-生产者问题,我希望得到如下输出:
Put: 0
Get: 0
Put: 1
Get: 1
....等等。
但与此相反,Consumer 类多次使用相同的 q 值,尽管使用了 wait() 和 notification() 方法..以及 Producer 类超出了消费者。如何获得同步输出?

这是 QFixed 类:(定义了 put() 和 get() 方法)

class QFixed{
    int n;
    boolean valueset = false;

    synchronized int get(){
        if(!valueset){
            try {
                wait();
            } catch (InterruptedException ex) {
                System.out.println("interrupted");
            }
        }
        System.out.println("Got: " +n);
        valueset = false;
        notify();
        return n;
    }

    synchronized void put(int n){
        if (valueset){
            try {
                wait();
            } catch (InterruptedException ex) {
                System.out.println("interrupted");
            }
        }
        this.n = n;
        valueset = true;
        System.out.println("Put: "+n);
        notify();
    }
}

这是 ProducerFixed 类:

class ProducerFixed implements Runnable{
    Q q;
    Thread t;
    public volatile boolean flag = true;
        ProducerFixed(Q q){
            this.q = q;
            t = new Thread(this,"Producer");
            t.start();
        }

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

    void stop() {
        flag = false;
    }
}

这是 ConsumerFixed 类:

class ConsumerFixed implements Runnable{
    Q q;
    Thread t;
    public volatile boolean flag = true;

        ConsumerFixed(Q q){
            this.q = q;
            t = new Thread(this,"Consumer");
            t.start();
        }

    @Override
        public void run(){
            while(flag){
                q.get();
            }
        }

    public void stop() {
        flag = false;
    }
}

这是 Producer_Consumer_Fixed 类:

public class Producer_Consumer_Fixed {
    public static void main(String arg[]){
        Q q = new Q();
        Producer p = new Producer(q);
        Consumer c = new Consumer(q);

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.out.println("interrupted");
        }

        p.stop();
        c.stop();
        try{
            p.t.join();
            c.t.join();
        }catch(InterruptedException e){
            System.out.println("interrupted");
        }
    }
}

QFixed get 和 put 方法中使用的习惯用法if (flag) wait已损坏,您应该使用 while 循环。看有关受保护块的 Oracle 教程 http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html.

一旦我更改了类的名称以删除“固定”,并替换if with while在Q类中,像这样:

class Q {
    int n;
    boolean valueset = false;

    synchronized int get(){
        while(!valueset){
            try {
                wait();
            } catch (InterruptedException ex) {
                System.out.println("interrupted");
            }
        }
        System.out.println("Got: " +n);
        valueset = false;
        notify();
        return n;
    }

    synchronized void put(int n){
        while (valueset){
            try {
                wait();
            } catch (InterruptedException ex) {
                System.out.println("interrupted");
            }
        }
        this.n = n;
        valueset = true;
        System.out.println("Put: "+n);
        notify();
    }
}

我得到的输出开始于

Put: 0
Got: 0
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
Put: 6
Got: 6
Put: 7
Got: 7
Put: 8
Got: 8
Put: 9
Got: 9
Put: 10
Got: 10
...

其中每个值都被放置和获取一次,这就是您想要的输出。

使用 while 循环是一件好事的原因有很多。

等待线程放弃监视器,一旦它醒来,它必须重新获取监视器,然后才能继续退出等待方法。这意味着其他线程可以获取监视器并可能更改同步保护的数据的状态。一旦线程重新获取了监视器,它就需要再次检查条件,然后才能知道它认为收到通知的条件是否确实发生了。否则,线程将根据过时的信息决定要做什么。

在涉及三个或更多竞争线程的示例中,这将是一个大问题。然而,对于这个特定的情况,我没有看到有问题的操作顺序。

使用 while 循环的另一个原因是,线程退出等待并不一定意味着发生了通知。根据对象的 javadoc#wait http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait%28long%29:

线程还可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这种情况在实践中很少发生,但应用程序必须通过测试应导致线程被唤醒的条件来防止这种情况,并在条件不满足时继续等待。换句话说,等待应该总是在循环中发生,如下所示:

synchronized (obj) {
    while (<condition does not hold>)
        obj.wait(timeout);
    ... // Perform action appropriate to condition
}

这是由于 JVM 实现中的竞争条件造成的;正如文档所说,这种情况应该很少发生。但这可能是问题的根源,在没有通知的情况下等待返回可能会产生像您所看到的那样的多次获取的情况。

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

同步实现:Java 的相关文章

随机推荐

  • 如何处理 iPhone 中 uitableviewcell 上每个按钮的切换按钮

    我的代码运行良好 但仅适用于单个单元格 当我定义 5 行时 它仅适用于最后一个单元格 如果我点击 1 个单元格 则值displayimage仅在最后一个单元格上 它不显示我单击的位置以及我单击的单元格如何处理每个单元格的toogle按钮更改
  • 为什么我要使用 Enumerable.ElementAt() 而不是 [] 运算符?

    这似乎是一个愚蠢的问题 但我还没有找到答案 所以就在这里 在这两种情况下 如果您未能检查集合的边界 您将收到 超出范围 异常 这只是编码风格偏好吗 如果有人需要一个例子 List
  • 制作平台游戏,需要方法停止运行

    我正在用 Flash 制作一个平台游戏 我有一个目标类 该类包含目标精灵的代码 当你击中它时 它会继续游戏的下一部分 在目标构造函数内部 添加了2个事件监听器 它们如下 addEventListener Event ADDED beginC
  • 如何在Boost Spirit中设置最大递归

    使用 boost spirit 如果我有递归规则来解析括号 rule
  • Java - 等待和notifyAll

    当你对一个没有等待的对象调用notifyAll方法时会发生什么 应该有例外还是正常情况 正如您在这里所看到的 对未等待的对象调用notifyAll 不会产生任何效果
  • 如何在 Symfony2 数据库查询中使用 MATCH

    我正在为我的 Symfony2 项目构建一个搜索功能 并为其编写了 SQL 如下所示 SELECT dlc title dlc description dlc keywords FROM ShoutMainBundle Dlc dlc WH
  • 测量外部 CDN 资源的访问者 HTTP 缓存命中率

    我的网站使用几种常见的 CDN 托管资源 例如bootstrap css jquery js and fontawesome css 是否可以通过 JavaScript 获取信息 我的网站访问者在其 Web 浏览器中是否有这些资源的热缓存
  • 以编程方式更改本地安全策略

    我想在 C 中更改本地安全策略 交互式登录 不需要 ctrl alt del 我怎样才能做到这一点 我找到了我必须在注册表中更改的答案 Windows 注册表编辑器版本 5 00 HKEY LOCAL MACHINE SOFTWARE Mi
  • Git 子模块工作流程问题

    最近 我们的 Git 存储库遇到了很多问题 我们是应用程序之间总共 4 个共享存储库的 git 子模块的用户 例如 存储库 网站 共有 3 个子模块 submodule vendor api path vendor api url emai
  • ionChange - 仅检测 Ionic 2 中从视图到模型的变化

    我有一个 Ionic 2 应用程序 允许安排通知 提醒功能 嗯 要求是 当用户进入提醒页面时 应该检查是否有 已保存提醒 如果有已保存的提醒 我目前正在保存此信息 存储 时钟应显示并保存提醒时间 切换开关处于活动状态 否则 时钟应显示当前时
  • 如何消除 WinForms 滚动动画中的抖动现象?

    我正在用 C 编写一个简单的控件 其工作方式类似于图片框 只不过图像不断向上滚动 并从底部重新出现 动画效果由计时器 System Threading Timer 驱动 该计时器从缓存的图像 分两部分 复制到隐藏缓冲区 然后在其 Paint
  • Gradle:“无法缓存配置缓存状态”

    Configuration cache state could not be cached field actions from type org gradle api DefaultTask error writing value of
  • Java 中的 IEqualityComparer 接口

    更具体地说 我想要一个接口来比较只能比较相等性的对象 例如复数 但没有全序 它应该有 注意它只返回一个布尔值是 否 boolean Equals T object1 T object2 和一个哈希码函数 这样 当我使用对象 例如收集 相等
  • 如何使用 Unix 或 Windows 风格的换行符 [重复]

    这个问题在这里已经有答案了 我正在阅读stdin有时有 UNIX 风格的换行符 有时是 Windows 风格的换行符 如何使用任一类型的换行符 假设您知道会有换行符 解决方案是消耗一个字符 然后决定 10 LF Unix style new
  • Mongo 查询数组中的嵌套字段。

    我有一个具有以下结构的文档 id fkwjefioew genres id fewkjfewf name Shooter 我需要能够使用 mongo 的 in 进行查询 以查看文档是否具有传递参数的流派名称 例如 如果我将 Shooter
  • Jest.js 错误:“已收到:序列化为同一字符串”

    我在这个测试中遇到了一个奇怪的问题 交易测试 js import Deal from src models Deal import apiProducts from mocks api products describe Deal gt d
  • Python 浮点精度格式说明符

    假设我有一些 32 位数字和一些 64 位数字 gt gt gt import numpy as np gt gt gt w np float32 2 4 gt gt gt x np float32 4 555555555555555 gt
  • 模拟 API 请求 Xcode 7 Swift 自动化 UI 测试

    在 Swift 2 0 中编写自动化 UI 测试时 有没有办法模拟请求 据我所知 UI 测试应该独立于其他功能 有没有办法模拟服务器请求的响应 以便测试依赖于响应的 UI 行为 例如 如果服务器关闭 UI 测试仍应运行 简单的示例 对于登录
  • 如何在远程主机中运行 bash function()?在 Ubuntu 中[重复]

    这个问题在这里已经有答案了 我正在运行一个bash脚本 但是当我尝试在远程计算机上运行函数时 它说 bash keyConfig command not found 这是我的脚本 keyConfig sed i bak r 1 s 1 2
  • 同步实现:Java

    这是一个消费者 生产者问题 我希望得到如下输出 Put 0 Get 0 Put 1 Get 1 等等 但与此相反 Consumer 类多次使用相同的 q 值 尽管使用了 wait 和 notification 方法 以及 Producer