java - ConcurrentHashMap迭代保证

标签 java multithreading synchronization concurrenthashmap

给定 ConcurrentHashMap javadocs 状态:

"Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator"

我想我可以保证在下面的示例中一个或两个线程都会调用 fireAllFinished()。是否会出现两者都不调用 fireAllFinished() 的情况?

ConcurrentHashMap<String, Boolean> taskToFinished = new ConcurrentHashMap();
    taskToFinished.put("taskA", false);
    taskToFinished.put("taskB", false);

public void checkForAllFinished() {
    boolean allFinished = true;
    for (Boolean taskFinished = tasksToFinished.values()) {
        if (!taskFinished) {
            allFinished = false;
            break;
        }
    }
    if (allFinished) {
       fireAllFinished()
    }
}

//Thread1
public void run() {
    taskToFinished.put("taskA", true);
    checkForAllFinished();
}

//Thread1
public void run() {
    taskToFinished.put("taskB", true);
    checkForAllFinished();
}

(我省略了一些线程创建代码。我希望意图很清楚)

更新:我已经看到了这个更普遍的问题:Is iterating ConcurrentHashMap values thread safe? ,但想确认我的具体观点

"at some point"

在处理无序运行代码的多核机器时,通常是一个不精确的概念,两个线程可能“同时”更新映射的不同段,并且设计上无法锁定整个 ConcurrentHashMap。

最佳答案

阅读 ConcurrentHashMap 的文档...

Retrievals reflect the results of the most recently completed update operations holding upon their onset. (More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.)

For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration.

措辞不清楚,但最近完成自或之后应该意味着映射操作和迭代器创建是顺序一致的。

使用您的示例,如果我们调用映射 put A,并值检查 B,您有...

T1:A -> B

T2:A -> B

A 先于 B 发生,但 T1T2 同时发生。顺序一致意味着只要 AB 之前发生,两者之间就需要出现某个有效顺序。但是,T1T2 之间的任何排序都是有效的。

例如

T1:A -> T1:B -> T2:A -> T2:B

T1:A -> T2:A -> T2:B -> T1:B

因此,当代码实际运行时,任何有效的排序都可能发生,但 T1:BT2:B (检查)必须最后发生。因此,fireAllFinished 会被调用一次或两次。线性同步将进一步限制所有事件之间的显式排序。

迭代整个 map 可能有点昂贵,而且仅使用 AtomicInteger 可能会更简单。或其他同步机制,如 ConcurrentLinkedQueue .

关于java - ConcurrentHashMap迭代保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33191084/

相关文章:

node.js - 带有 elasticsearch 的 Postgres(保持同步)- nodeJS

Java 泛型和集合

java - 在 switch 中使用数组作为 case 语句

java - log4j2 配置不会加载自定义模式转换器

java - 设计AppServer面试讨论

Java 线程无法与链表正常工作

java - rJava 无法安装在 openSUSE 13.2 上

java - 停止/中断线程在等待来自套接字的输入时阻塞

c# - 使用 FileSystemWatcher 时 c# GUI 中的内存不足异常 - 多线程

swift - 按顺序 Swift 执行任务