LinkedBlockingQueue的insert和remove方法线程安全吗?

问题描述 投票:0回答:3

我在两个不同的线程之间使用

LinkedBlockingQueue
。一个线程通过
add
添加数据,而另一个线程通过
take
接收数据。

我的问题是,我是否需要同步访问

add
take
LinkedBlockingQueue
的插入和删除方法线程安全吗?

java multithreading concurrency synchronization
3个回答
68
投票

是的。 来自文档

“BlockingQueue 实现是 线程安全。所有排队方式 使用原子方式实现其效果 内部锁或其他形式的 并发控制。然而,大部分 集合操作addAll, containsAll、retainAll 和 removeAll 不一定执行 除非另有说明,否则以原子方式 在一个实现中。原来如此 可能,例如,对于 addAll(c) 之后失败(抛出异常) 仅添加其中的一些元素 c.”

编辑:

addAll
行为不是多线程特定的问题,因为单线程场景可能会出现完全相同的问题。

在单线程应用程序中,创建一个 ArrayList

list
,其中包含 9 个非空元素,末尾有 1 个空元素。

致电

queue.addAll(list);

假设它按顺序添加元素(我不相信这是保证的,但很可能会),它将添加前 9 个元素,然后抛出异常。 (BlockingQueue 不允许空元素。)9 仍会添加到队列中。

  1. 要求
    addAll
    是原子的,无论集合是否是线程安全的,都要求很高。它需要对整个集合进行快照然后回滚。 是的,它可以为许多集合实现(尽管对于某些集合来说会很复杂),但我不认为任何集合(线程安全与否)都可以实现。

底线:集合很复杂,而且它们的保证也各不相同。 查阅文档很重要。 线程安全只是许多人关心的问题之一。


17
投票

是的,

BlockingQueue
方法
add()
take()
是线程安全的但有区别

add ()
take()
方法使用 2 个不同的
ReentrantLock
对象。

add(
)方法使用

private final ReentrantLock putLock = new ReentrantLock();

take()
方法使用

private final ReentrantLock takeLock = new ReentrantLock();

因此,对

add()
方法的同时访问是同步的。同样,同时访问
take()
方法是
synchronized

但是,同时访问

add()
take()
方法不是
synchronized
,因为它们使用 2 个不同的锁定对象(队列满/空的边缘条件除外)。


-1
投票

简单地说,它绝对是线程安全的,否则它就没有资格作为 ThreadPoolExecutor 存储元素的候选者。

只需添加和检索元素,无需担心 BlockingQueue 的并发性。

© www.soinside.com 2019 - 2024. All rights reserved.