Java中的BlockingQueue是完全线程安全的吗

2024-04-02

我知道文档说该对象是线程安全的,但这是否意味着从所有方法对它的所有访问都是线程安全的?所以如果我打电话put()同时从多个线程上进行操作take()在同一时刻,不会有什么不好的事情发生吗?

我问这个问题是因为这个答案让我再次猜测:https://stackoverflow.com/a/22006181/4164238 https://stackoverflow.com/a/22006181/4164238


快速回答是肯定的,它们是线程安全的。但我们不要把它留在那里......

首先是一点家务管理,BlockingQueue是一个接口,任何非线程安全的实现都将违反记录的契约。您包含的链接指的是LinkedBlockingQueue,这有一些聪明之处。

The 您添加的链接 https://stackoverflow.com/questions/2695426/are-linkedblockingqueues-insert-and-remove-methods-thread-safe/22006181#22006181做了一个有趣的观察,是的,里面有两把锁LinkedBlockingQueue。然而,它无法理解“简单”实现可能遇到的边缘情况实际上正在被处理,这就是为什么 take 和 put 方法比人们最初预期的更复杂的原因。

LinkedBlockingQueue进行了优化以避免在读取和写入时使用相同的锁,这减少了争用,但是为了正确的行为,它依赖于队列不为空。当队列中有元素时,推入点和弹出点不在同一内存区域,可以避免争用。然而,当队列为空时,争用就无法避免,因此需要额外的代码来处理这种常见的“边缘”情况。这是代码复杂性和性能/可扩展性之间的常见权衡。

那么问题来了,如何LinkedBlockingQueue知道队列何时为空/非空,从而处理线程?答案是它使用一个AtomicInteger and a Condition作为两个额外的并发数据结构。这AtomicInteger用于检查队列的长度是否为零,条件用于等待信号以在队列可能处于所需状态时通知等待线程。这种额外的协调确实会产生开销,但在测量中表明,当增加并发线程的数量时,该技术的开销低于使用单个锁引入的争用。

下面我复制了代码LinkedBlockingQueue并添加了解释它们如何工作的评论。在高水平上,take()首先锁定所有其他调用take()然后发出信号put()有必要的。put()以类似的方式工作,首先它会阻止所有其他调用put()然后发出信号take()如果需要的话。

来自put() method:

    // putLock coordinates the calls to put() only; further coordination
    // between put() and take() follows below
    putLock.lockInterruptibly();
    try {
        // block while the queue is full; count is shared between put() and take()
        // and is safely visible between cores but prone to change between calls
        // a while loop is used because state can change between signals, which is
        // why signals get rechecked and resent.. read on to see more of that 
        while (count.get() == capacity) { 
                notFull.await();
        }

        // we know that the queue is not full so add
        enqueue(e);
        c = count.getAndIncrement();

        // if the queue is not full, send a signal to wake up 
        // any thread that is possibly waiting for the queue to be a little
        // emptier -- note that this is logically part of 'take()' but it
        // has to be here because take() blocks itself
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();

From take()

    takeLock.lockInterruptibly();
    try {
            // wait for the queue to stop being empty
            while (count.get() == 0) {
                notEmpty.await();
            }

        // remove element
        x = dequeue();

        // decrement shared count
        c = count.getAndDecrement();

        // send signal that the queue is not empty
        // note that this is logically part of put(), but
        // for thread coordination reasons is here
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java中的BlockingQueue是完全线程安全的吗 的相关文章

随机推荐

  • 如何在 SQLite 查询中使用正则表达式?

    我想在 sqlite 中使用正则表达式 但我不知道如何 我的表有一列包含如下字符串 3 12 13 14 19 28 32 现在 如果我输入 where x LIKE 3 我还会得到包含 13 或 32 等值的行 但我只想获取该字符串中恰好
  • 以编程方式在 UITableViewCell 中呈现带有按钮的视图控制器 (Swift)

    I am trying to make it where when a user clicks on a table view cell in my table view it takes them to a new view contro
  • Outlook 插件 - 获取当前选定的日历日期

    当右键单击日历并运行功能区操作时 是否可以像获取当前邮件项或约会项一样获取选定的日历日期 功能区 XML
  • 是否可以将组件作为 props 传递并在 Vue 的子组件中使用它?

    在 Vue 2 0 应用程序中 假设我们有组件 A B 和 C A声明 注册并使用B 是否可以将C从A传递到B 像这样的事情
  • 如何取消numpy seed()的效果?

    我想在程序的第一部分使用 np random seed 并在第二部分取消它 再次 在我的 python 文件的第一部分中 我希望在每次执行时生成相同的随机数 在第二部分中 我希望在每次执行时生成不同的随机数 在第一部分中 使用常量初始化种子
  • Exchange Web 服务附件加载缓慢

    我正在编写一些代码来下载和处理电子邮件的附件 然后处理它们 该代码在某些情况下可以按要求工作 但仍然存在一些重大问题 每当代码将附件加载到本地磁盘上的文件中时 都会花费很长的时间 并且经常会由于下载缓慢而超时 并出现以下异常 A first
  • 意外查询成功

    SELECT COUNT FROM rps2 workflow WHERE workflow added gt TO DATE 01 09 2011 dd mm yyyy AND workflow finished lt TO DATE w
  • 如何将 system.data.SQLite.dll 的引用添加到 Windows Phone 7

    我是 Windows Phone 7 的新手 请帮我解决这个问题 我想在Windows Phone 7中添加SQLite数据库 我下载了system data SQLite dll 来自sourceforge www sqlite org
  • 蓝鸟承诺解析(数据)在客户端代码中未定义

    希亚斯 我有一个简单的应用程序 客户端期望得到一个承诺作为结果 但是在调用resolve 方法时 承诺不断返回未定义的结果 客户端代码 UsersRepo findOneAsync id id then function err resul
  • 为函数想出好的名字时遇到困难

    因此 我经常难以用简洁的名称描述函数 对于重用的功能来说 这通常不是问题 但通常需要将大型流程分解为子功能 这些通常会得到奇怪的名字 例如connectionsToAccessLines or handleWallVisionSplit或类
  • 在 C 预处理器中,“#”字符是否必须位于行的开头? [复制]

    这个问题在这里已经有答案了 我已经用 C 语言编程有一段时间了 在此期间 我了解到将预处理器指令之前的 字符放在第一列是一种常见的约定 Example include
  • 如何在 Foursquare Venues 搜索 API 中使用 CategoryId

    当包含categoryId参数时 我从API查询中得到了意外的结果 例如 当使用以下参数搜索马萨诸塞州波士顿的 The Citizen Public House 时 ll 42 3489027315987 71 096134185791 q
  • random.expovariate 相当于泊松过程

    我在某处读到 python 库函数 random expovariate 产生相当于泊松过程事件的间隔 真的是这样吗 或者我应该对结果施加一些其他功能 严格阅读你的问题 是的 这就是 random expovariate 所做的 expov
  • 什么是热点?

    我刚刚听说过 HotSpot JVM 而不是 Oracle JRockik JVM 什么是热点 这是旧的 Sun JVM 还是其他什么 HotSpot 是附带的 Sun JVM 它支持频繁使用的代码部分的即时编译 出于所有实际目的 它是 S
  • 如何从消息机器人中删除“Powered by ManyChat”页脚

    我正在为消息平台开发一个聊天机器人 但我发现自己对用户文本输入字段的页脚上出现的 ManyChat 感到着迷 我已成为该页面的管理员 并继续从该页面的已连接应用程序列表中删除许多聊天 但页脚仍然存在 也许我必须调用 Messenger 平台
  • 是否可以验证html5中input=file的大小和类型

    我正在读这个http dev w3 org html5 markup input file html http dev w3 org html5 markup input file html 但我只找到了 accept 属性 我试过这个
  • Python:检查对象是否是序列

    在 python 中 有没有一种简单的方法来判断某些东西是否不是序列 我尝试这样做 if x is not sequence但Python不喜欢那样 iter x 将提出一个TypeError if x不能迭代 但该检查 接受 集合和字典
  • 获取我的应用程序的当前 dot net 版本

    如何获取我的 asp net 应用程序的正在运行的 dot net 版本 我尝试了这里的解决方案 有没有一种简单的方法来检查 NET Framework 版本 https stackoverflow com questions 951856
  • 如何解决 HttpURLConnection 上的 NullPointerException?

    我正在开发一个Android应用程序 使用ExoPlayer进行视频播放 使用Glide进行图像显示 使用下载库进行文件下载 它们都有与HttpURLConnection相关的NullPointerException 我确信使用的链接是可用
  • Java中的BlockingQueue是完全线程安全的吗

    我知道文档说该对象是线程安全的 但这是否意味着从所有方法对它的所有访问都是线程安全的 所以如果我打电话put 同时从多个线程上进行操作take 在同一时刻 不会有什么不好的事情发生吗 我问这个问题是因为这个答案让我再次猜测 https st