本文介绍了在get()返回null之前,ConcurrentMap.remove()是否提供了before-before。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在调用 ConcurrentMap.remove()之前的一个线程中的操作是否保证之后发生操作,之后看到从另一个线程中删除?

Are actions in a thread prior to calling ConcurrentMap.remove() guaranteed to happen-before actions subsequent to seeing the removal from another thread?

说明了关于置于集合中的对象:

Documentation says this regarding objects placed into the collection:

示例代码:

{
    final ConcurrentMap map = new ConcurrentHashMap();
    map.put(1, new Object());

    final int[] value = { 0 };

    new Thread(() -> {
        value[0]++;
        value[0]++;
        value[0]++;
        value[0]++;
        value[0]++;

        map.remove(1); // A

    }).start();

    new Thread(() -> {
        if (map.get(1) == null) { // B
            System.out.println(value[0]); // expect 5
        }

    }).start();
}

中的 A 发生 - 在与 B 关系之前?因此,如果该程序只打印5?

Is A in a happens-before relationship with B? Therefore, should the program only, if ever, print 5?

推荐答案

您已经发现这些并发工具的一个有趣的细微方面,容易被忽视。

You have found an interesting subtle aspect of these concurrency tools that is easy to overlook.

首先,不可能提供关于删除和检索 null 的一般保证引用,因为后者只能证明映射的缺席而不是先前的删除,即线程可能已经读取了映射的初始状态,而密钥曾经有映射当然,它无法与地图构造后发生的动作建立发生之前的关系。

First, it’s impossible to provide a general guaranty regarding removal and the retrieval of a null reference, as the latter only proves the absence of a mapping but not a previous removal, i.e. the thread could have read the map’s initial state, before the key ever had a mapping, which, of course, can’t establish a happens-before relationship with the actions that happened after the map’s construction.

此外,如果有多个线程删除相同的密钥,在检索 null 时,您不能假设发生在之前的关系,因为您不知道哪个删除已经完成。此问题类似于两个线程插入相同值的情况,但后者可以通过仅执行可区分值的插入或通过遵循对值对象执行所需修改的常规模式在应用程序端修复要插入并仅查询检索到的对象。对于删除,没有这样的修复。

Also, if there are multiple threads removing the same key, you can’t assume a happens-before relationship, when retrieving null, as you don’t know which removal has been completed. This issue is similar to the scenario when two threads insert the same value, but the latter can be fixed on the application side by only perform insertions of distinguishable values or by following the usual pattern of performing the desired modifications on the value object which is going to be inserted and to query the retrieved object only. For a removal, there is no such fix.

在您的特殊情况下,发生之前的关系> map.put(1,new Object()) action和第二个线程的开始,所以如果第二个线程在查询时遇到 null 密钥 1 ,很明显它见证了你的代码的唯一删除,但规范并没有为这个特殊情况提供明确的保证。

In your special case, there’s a happens-before relationship between the map.put(1, new Object()) action and the start of the second thread, so if the second thread encounters null when querying the key 1, it’s clear that it witnessed the sole removal of your code, still, the specification didn’t bother to provide an explicit guaranty for this special case.

相反,说,

明确排除 null 检索。

我认为使用当前(Java 8) ConcurrentHashMap 实现,您的代码无法破解,因为它使用<$ c执行对其内部后备阵列的所有访问$ c> volatile 语义。但这只是当前的实现,并且如上所述,您的代码是一个特殊情况,并且可能会因为对实际应用程序的每次更改而破坏。

I think, with the current (Java 8) ConcurrentHashMap implementation, your code can’t break as it is rather conservative in that it performs all access to its internal backing array with volatile semantics. But that is only the current implementation and, as explained above, your code is a special case and likely to become broken with every change towards a real-life application.

这篇关于在get()返回null之前,ConcurrentMap.remove()是否提供了before-before。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 09:19