Java 8 并发 HashMap

标签 java concurrency

我观察到 ConcurrentHashMap 已在 Java 8 中完全重写,变得更加“无锁”。我浏览了 get() 的代码方法并查看没有显式锁定机制:

public V get(Object key) {
    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    int h = spread(key.hashCode());
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (e = tabAt(tab, (n - 1) & h)) != null) {
        if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
        }
        else if (eh < 0)
            return (p = e.find(h, key)) != null ? p.val : null;
        while ((e = e.next) != null) {
            if (e.hash == h &&
                ((ek = e.key) == key || (ek != null && key.equals(ek))))
                return e.val;
        }
    }
    return null;
}

问题:

如何从一个线程看到其他线程对此 HashMap 所做的修改,因为代码不在同步伞下(这将强制执行先发生关系)?

注意:整个 ConcurrentHashMap 是一个表的包装器: transient volatile Node<K,V>[] table;

所以 table是对数组的 volatile 引用,而不是对 volatile 元素数组的引用! 这意味着如果有人正在更新此数组中的元素,则不会在其他线程中看到该修改。

最佳答案

简答

Node#valvolatile,它在订购之前确定您的发生情况。

更长的答案

synchronized 不是线程安全的要求,它是工具箱中用于确保系统线程安全的一种工具。您必须考虑对此 ConcurrentHashMap 执行的一整套操作,以推断线程安全性。

了解原始 ConcurrentHashMap 也是非阻塞的很有用。注意 Java 8 之前的 CHM get

V get(Object key, int hash) {
    if (count != 0) { // read-volatile
        HashEntry<K,V> e = getFirst(hash);
        while (e != null) {
            if (e.hash == hash && key.equals(e.key)) {
                V v = e.value;
                if (v != null)
                    return v;
                return readValueUnderLock(e); // ignore this
            }
            e = e.next;
        }
    }
    return null;
}

在这种情况下,没有阻塞,那么它是如何工作的呢? HashEntry#valuevolatile。那是线程安全的同步点。

CHM-8 的 Node 类是相同的。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;

因此,在这种情况下,非 null val 应确保您在放置之前的操作方面发生先行关系。

关于Java 8 并发 HashMap ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44460503/

相关文章:

java - 有趣的 Java 正则表达式限制

java - 我怎样才能获得 Caps Lock 状态,并将其设置为打开状态(如果尚未打开)?

java - 检查整数值是否增加?

java - SpringBoot进程运行时性能问题

scala - 由于某种原因无法从 RejectedExecutionException 中恢复

java - 正则表达式模式的困难

java - 在任务栏中的 PopupMenu 中添加垂直分隔符

java - 解决Java Oracle并发更新/删除语句

java - 在这种情况下,同步语句如何工作?

java - Java多线程和文件