java中使用wait()和notify()的简单场景

2023-12-28

我可以获得一个完整的简单场景,即建议如何使用它的教程,特别是使用队列?


The wait() and notify()方法旨在提供一种机制,允许线程阻塞直到满足特定条件。为此,我假设您想要编写一个阻塞队列实现,其中有一些固定大小的元素后备存储。

您要做的第一件事是确定您希望方法等待的条件。在这种情况下,您将需要put()方法进行阻塞,直到存储中有可用空间,并且您将需要take()方法阻塞,直到有一些元素要返回。

public class BlockingQueue<T> {

    private Queue<T> queue = new LinkedList<T>();
    private int capacity;

    public BlockingQueue(int capacity) {
        this.capacity = capacity;
    }

    public synchronized void put(T element) throws InterruptedException {
        while(queue.size() == capacity) {
            wait();
        }

        queue.add(element);
        notify(); // notifyAll() for multiple producer/consumer threads
    }

    public synchronized T take() throws InterruptedException {
        while(queue.isEmpty()) {
            wait();
        }

        T item = queue.remove();
        notify(); // notifyAll() for multiple producer/consumer threads
        return item;
    }
}

关于使用等待和通知机制的方式,有几点需要注意。

首先,您需要确保任何调用wait() or notify()位于代码的同步区域内(带有wait() and notify()在同一对象上同步调用)。造成这种情况的原因(除了标准线程安全问题之外)是由于丢失信号造成的。

一个例子是,线程可以调用put()当队列碰巧已满时,它会检查条件,发现队列已满,但在它可以阻止另一个线程被调度之前。然后第二个线程take()是队列中的一个元素,并通知等待线程队列不再满。然而,因为第一个线程已经检查了条件,所以它只会调用wait()重新安排后,尽管可以取得进展。

通过在共享对象上同步,您可以确保不会发生此问题,因为第二个线程的take()在第一个线程实际阻塞之前,调用将无法取得进展。

其次,由于存在虚假唤醒问题,您需要将要检查的条件放入 while 循环中,而不是 if 语句中。这是有时可以重新激活等待线程而无需notify()被召唤。将此检查放在 while 循环中将确保如果发生虚假唤醒,将重新检查条件,并且线程将调用wait() again.


正如其他一些答案所提到的,Java 1.5 引入了一个新的并发库(在java.util.concurrent包),旨在为等待/通知机制提供更高级别的抽象。使用这些新功能,您可以像这样重写原始示例:

public class BlockingQueue<T> {

    private Queue<T> queue = new LinkedList<T>();
    private int capacity;
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    public BlockingQueue(int capacity) {
        this.capacity = capacity;
    }

    public void put(T element) throws InterruptedException {
        lock.lock();
        try {
            while(queue.size() == capacity) {
                notFull.await();
            }

            queue.add(element);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public T take() throws InterruptedException {
        lock.lock();
        try {
            while(queue.isEmpty()) {
                notEmpty.await();
            }

            T item = queue.remove();
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }
}

当然,如果您确实需要一个阻塞队列,那么您应该使用阻塞队列 http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html界面。

另外,对于这样的东西我强烈推荐Java 并发实践 http://www.amazon.co.uk/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601,因为它涵盖了您可能想了解的有关并发相关问题和解决方案的所有内容。

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

java中使用wait()和notify()的简单场景 的相关文章

随机推荐

  • iPython - 在配置文件中设置魔法命令

    我主要通过笔记本使用 iPython 但也在终端中使用 我刚刚通过运行创建了我的默认配置文件ipython profile create 我似乎无法弄清楚如何让配置文件运行我每次使用的几个神奇命令 我试图在网上和我正在读的书中查找这一点 但
  • 如何使用 Spring Data 获取数据

    嘿 我想创建一个扩展 JpaRepository 的存储库并获取结果而不编写实际查询 在我的示例中 我有 2 个表 Book 和 Author 通过多对多关系映射 假设我想按特定的author id 获取书籍列表 因为在我的书籍实体中 我没
  • 无法在 Vim 中映射

    周末拿到了我的第一台 Mac 我正在努力适应 我的 vimrc 中的这一行在我的 Windows 上有效 但无法通过 iTerm 与 vim 一起工作 inoremap
  • 具有约束关联类型错误“类型不可转换”的 Swift 协议

    我创建了 2 个具有关联类型的协议 类型符合Reader应该能够生成符合以下类型的实例Value 复杂性层来自于符合以下条件的类型Manager应该能够生产混凝土Reader产生特定类型的实例Value 任何一个Value1 or Valu
  • */ 中 d 的 shell 脚本; do在本地运行,但在circleci中不起作用

    我构建了一个脚本 当我尝试在本地运行它时 它工作正常 但是当我在 Circleci 上运行它时 我收到错误 这是脚本 usr bin env bash for d in do cd d for f in do if f sh then if
  • 提示用户打开另一个工作簿

    我正在编写一个子程序 我需要用户打开特定的工作簿 因为我需要将数据从将打开的工作簿复制到运行该子程序的工作簿 由于将打开的文件是月度报告 因此用户很难始终将其以相同的文件名保存在同一位置 因此 如果要求用户打开工作簿 月度报告 那就太好了
  • VS Code 自动导入不使用绝对路径且不缩进

    我将 Typescript 与 SvelteKit 结合使用 当我输入可以自动导入的内容时 如上面的 GIF 所示 自动导入不会使内容保持相同的缩进级别 我还需要绝对路径 src not src VS 代码的设置称为 TypeScript
  • Magento 报告 - 产品 - 产品订购问题:具有相同 ID 的项目 (Mage_Catalog_Model_Product) 已存在

    问题 在 Magento 管理面板中 通过 报告 产品 订购的产品 生成报告时 会发生错误 Item Mage Catalog Model Product with the same id 45 already exist 0 home g
  • 读取文件中的每一行并将每一行放入一个字符串中

    我有一个文本文件 我想读入该文件并将文件中的每一行放入其自己的字符串中 所以该文件将有 4 行 2017 01 2005 59 30 353879833382971575 迈克尔 因此 在代码中 我需要读取文件并拆分每一行并将它们放入一个字
  • 垂直错开 div

    有没有办法像这张图片一样以交错的垂直排列方式显示 div 到目前为止 我已经使用 Flexbox 来接近 但无法交错行 因为我不想预先确定每行有多少个圆圈 我希望用户的浏览器宽度来控制每行有多少个圆圈 因此圆圈 div 上没有类或子项 随着
  • Play框架 路由不区分大小写

    我们目前正在开发 Play 2 5 x 我们希望实现不区分大小写的路由 比如说 GET via v1 organizations http organizationApi 在我们想要实现的URL中 http localhost 9000 a
  • MFC不支持小于0x0501的WINVER

    我有一个 C 项目引用了许多其他项目 库 这是针对多年前创建的应用程序 大约每年更新一次并完成新版本 我多年来一直使用 Visual Studio 6 更新和构建此应用程序的新版本 没有出现任何问题 我正在尝试切换到 Visual Stud
  • Python NLTK 多线程

    我正在编写一个算法 它可以识别给定文本中的句子 将每个句子拆分成单词并在经过一些验证后返回这些单词 我想在多线程的帮助下实现同样的功能 我正在调用处理每个句子的函数threading thread 它会抛出一个错误 AttributeErr
  • 如何在javascript中获取最高的输入字段值

    我想获得这个领域的最高价值 我怎样才能做到这一点
  • “始终开启”设置会阻止idleTimeout 和periodicRestart 吗?

    您可能知道 Microsoft Azure 网站服务下托管的网站默认配置为空闲 20 分钟后超时 idleTimeout 并且应用程序池每 29 小时重新启动一次 periodicRestart 这会导致第一个用户访问网站时速度很慢 我想知
  • 将 Recaptcha 与 EPiServer XForms 结合使用

    有人有在 EPiServer 中使用 Recaptcha 和 XForms 的经验吗 我不知道将 Recaptcha 控件放在哪里以及如何使其工作 ASP NET 的示例代码如下 我应该把它放在哪里 我的猜测是在FormControl Be
  • 多态推理

    我正在学习 Haskell 在互联网上我发现的是paper https people mpi sws org dreyer tor papers wadler pdf来自菲利普 瓦德勒 我读了它 但根本不明白 但它以某种方式与多态函数联系起
  • Internet Explorer CSS 问题

    This page http a accioly 7rtc com p tecnologia htmlIE 9 也可能是旧版本 无法正确呈现 右侧菜单浮动到页面底部 Firefox Chrome 和 Safari 可以正确渲染它 所有浏览器
  • DispatchQueue :无法在非主线程上使用 asCopy = NO 进行调用

    我正在介绍的是UIAlertController在主线程上为 class HelperMethodClass NSObject class func showAlertMessage message String viewControlle
  • java中使用wait()和notify()的简单场景

    我可以获得一个完整的简单场景 即建议如何使用它的教程 特别是使用队列 The wait and notify 方法旨在提供一种机制 允许线程阻塞直到满足特定条件 为此 我假设您想要编写一个阻塞队列实现 其中有一些固定大小的元素后备存储 您要