Does using a LinkedBlockingQueue between two threads mean we don't need to synchronize their access to shared data?

Ahm*_*mid 6 java multithreading

I have a situation where a project I'm maintaining contains a piece of code where:

  1. A thread T1 periodically updates a field of type List<String> then adds a value to a LinkedBlockingQueue:

    // ctor
    List<String> list = null;
    queue = new LinkedBlockingQueue(); // Integer.MAX_VALUE capacity
    
    // Thread T1
    list = getNewList();
    queue.offer(/* some value */);
    
    Run Code Online (Sandbox Code Playgroud)
  2. Another thread T2 periodically polls queue and, upon receiving a certain value, reads list:

    // Thread T2
    Object value = queue.poll();
    if (Objects.equals(value, /* some desired value */) {
        // Read `list` in (1)
    }
    
    Run Code Online (Sandbox Code Playgroud)

The thing that caught my attention was the lack of synchronization between the two threads as they accessed list (was not marked volatile either), which made me think there could be a data race in that code. However, when I referred to BlockingQueue, I found a sentence that says:

内存一致性影响:与其他并发集合一样,在将对象放入 BlockingQueue 之前线程中的操作发生在另一个线程中从 BlockingQueue 中访问或删除该元素之后的操作之前。

这是否意味着T2总能保证通过观察所做的更改T1list无数据竞争是可能的吗?

paf*_* k. 0

这是这里更普遍描述的效果的一个特殊实例(该页面上的内存一致性错误链接特别值得阅读。

\n\n

所有这些集合都通过定义将对象添加到集合的操作与访问或删除该对象的后续操作之间的发生之前关系来帮助避免内存一致性错误。

\n\n

因此,更一般地说,当您有两段如下代码时:

\n\n
// list is a non thread safe ArrayList\nlist.add("abcd");\n// col is *any* java.util.concurrent collection\ncol.add(anObject); // or put, or offer...\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
if (col.get() == anObject) { \xe2\x80\xa6 } // or poll etc.\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果第二段代码由第一段之外的其他线程执行(并且条件为真),则在检索后放置的任何代码都anObject可以看到“abcd”添加到列表中。

\n\n

但:

\n\n
    \n
  • 它必须是同一个对象(anObject即您从并发集合中放入/获取的内容)
  • \n
  • 假设col.addObject(anObject)调用后,列表没有进一步修改
  • \n
  • 它(显然,但值得注意)必须已实际放入集合中。offer()可能在另一个线程中返回 false 并且poll()可能在这个线程中超时。
  • \n
\n

  • `col.get(anObject);` 非常具有误导性,因为通常您不会告诉查询方法要返回什么。由于您正确命名了有关返回同一对象的查询的约束,因此使用 if(col.get() == anObject) { … }` 来演示唯一有效的用例是有意义的。还值得补充的是,它仅在“anObject”从未添加多次的情况下才有效,并且在“col.add(anObject);”操作之后不会对“list”或其元素进行任何修改。 (2认同)