ConcurrentHashMap 源码分析07之函数篇 get、compute方法详解

  • Post author:
  • Post category:其他




1. 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()); // 获得 hash 值
    /* tab 不为 null && tab数组长度 > 0 && tab对应桶位不为空 */
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (e = tabAt(tab, (n - 1) & h)) != null) {
        /* e 为 key 对应的节点 */
        if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
        }
        /* 转移节点 or 树节点 or null */
        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; // 未找到返回 null
}



2. getOrDefault

  • 获取到则返回 value,获取不到(即 null) 返回指定的默认值
public V getOrDefault(Object key, V defaultValue) {
    Vv;
    return (v = get(key)) == null ? defaultValue : v;
}



3. compute

  • 给定 key 值找到节点 p,与 remappingFunction(key, value) 生成的 val 值

    • p 为 null,val 为null :没有改变,相当于无需进行操作
    • p 为 null,val 不为null :新添加节点 Node(key, val)
    • p 不为 null,val 为null :相当于删除 key 对应的节点
    • p 不为 null,val 不为null :相当于更换 p 的 value 值
public V compute(K key,
                 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    /* null 异常检测 */             
    if (key == null || remappingFunction == null)
        throw new NullPointerException();
    /* 获取 hash 值 */    
    int h = spread(key.hashCode());
    V val = null;
    int delta = 0; // 对应的 count 变化计数
    int binCount = 0; // 当前桶位的节点个数计数,用于判断链表是否需要树化
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        /* tab 还未初始化 */
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        /* 对应的桶位节点为 null */    
        else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
            Node<K,V> r = new ReservationNode<K,V>();
            synchronized (r) {
            	/* CAS设置 tab[i] 的值为 r */
                if (casTabAt(tab, i, null, r)) {
                    binCount = 1;
                    Node<K,V> node = null;
                    try {
                    	/* 若 val 为null,不 new 新节点,因为 ConcurrentHashMap 的 key,value 都不能为 null*/
                        if ((val = remappingFunction.apply(key, null)) != null) {
                            delta = 1;
                            node = new Node<K,V>(h, key, val, null);
                        }
                    } finally {
                        setTabAt(tab, i, node); // 设置桶位首节点
                    }
                }
            }
            /* binCount == 0 代表当前位置已被其他线程设置值 */
            if (binCount != 0)
                break;
        }
        /* 当前tab正在扩容,先帮助扩容 */
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            synchronized (f) {
                if (tabAt(tab, i) == f) {
                	/* 链表节点 */
                    if (fh >= 0) {
                        binCount = 1;
                        for (Node<K,V> e = f, pred = null;; ++binCount) {
                            K ek;
                            /* 找到 key 对应的节点 */
                            if (e.hash == h &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                val = remappingFunction.apply(key, e.val);
                                /* 若 val 不为null,相当于更改节点的value值 */
                                if (val != null)
                                    e.val = val;
                                else {
                                	/* 若 val 为null,相当于删除该节点 */
                                    delta = -1;
                                    Node<K,V> en = e.next;
                                    if (pred != null)
                                        pred.next = en;
                                    else
                                        setTabAt(tab, i, en);
                                }
                                break;
                            }
                            pred = e;
                            /*找不到key对应的节点,若 val 不为null,添加一个节点 */
                            if ((e = e.next) == null) {
                                val = remappingFunction.apply(key, null);
                                if (val != null) {
                                    delta = 1;
                                    pred.next =
                                        new Node<K,V>(h, key, val, null);
                                }
                                break;
                            }
                        }
                    }
                    /* 树节点 */
                    else if (f instanceof TreeBin) {
                        binCount = 1;
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> r, p;
                        if ((r = t.root) != null)
                            p = r.findTreeNode(h, key, null);
                        else
                            p = null;
                        V pv = (p == null) ? null : p.val;
                        val = remappingFunction.apply(key, pv);
                        /* val 不为null,找到节点p则替换value值,找不到则添加节点 */
                        if (val != null) {
                            if (p != null)
                                p.val = val;
                            else {
                                delta = 1;
                                t.putTreeVal(h, key, val);
                            }
                        }
                        /* val 为null,相当于删除节点 */
                        else if (p != null) {
                            delta = -1;
                            if (t.removeTreeNode(p))
                                setTabAt(tab, i, untreeify(t.first));
                        }
                    }
                }
            }
            /* binCount > 默认树化节点=8 则进行树化 */
            if (binCount != 0) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                break;
            }
        }
    }
    /* delta 不为0,则进行对应count计数,删除的 delta 为负数 */
    if (delta != 0)
        addCount((long)delta, binCount);
    return val;
}



4. computeIfAbsent

  • 给定 key 值找到节点 p,与 remappingFunction(key) 生成的 val 值

    • p 为 null,val 为null :没有改变,相当于无需进行操作
    • p 为 null,val 不为null :新添加节点 Node(key, val)
    • p 不为 null,val 为null :返回 val 值
    • p 不为 null,val 不为null :返回 val 值
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
	/* null 异常检测 */
    if (key == null || mappingFunction == null)
        throw new NullPointerException();
    int h = spread(key.hashCode()); // 获取 hash 值
    V val = null;
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        /* tab 未初始化 */
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        /* 对应的桶位节点为 null */    
        else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
            Node<K,V> r = new ReservationNode<K,V>();
            synchronized (r) {
            	/* CAS设置 tab[i] 的值为 r */
                if (casTabAt(tab, i, null, r)) {
                    binCount = 1;
                    Node<K,V> node = null;
                    /* 若val不为null,新添加一个节点,并将该节点设置为桶位首节点 */
                    try {
                        if ((val = mappingFunction.apply(key)) != null)
                            node = new Node<K,V>(h, key, val, null);
                    } finally {
                        setTabAt(tab, i, node);
                    }
                }
            }
            /* 若 binCount == 0 代表 CAS 设置失败 */
            if (binCount != 0)
                break;
        }
        /* 若当前tab正在扩容,先帮助扩容 */
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            boolean added = false;
            synchronized (f) {
            	/* 加锁后先判断 首节点f 有没有被修改 */
                if (tabAt(tab, i) == f) {
                	/* 链表节点 */
                    if (fh >= 0) {
                        binCount = 1;
                        for (Node<K,V> e = f;; ++binCount) {
                            K ek; V ev;
                            /* e 为key对应的节点,修改 e 的 value 值 */
                            if (e.hash == h &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                val = e.val;
                                break;
                            }
                            Node<K,V> pred = e;
                            /* 找不到key对应的节点,val不为 null 则在末尾添加新节点 */
                            if ((e = e.next) == null) {
                                if ((val = mappingFunction.apply(key)) != null) {
                                    added = true;
                                    pred.next = new Node<K,V>(h, key, val, null);
                                }
                                break;
                            }
                        }
                    }
                    /* 树节点 */
                    else if (f instanceof TreeBin) {
                        binCount = 2;
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> r, p;
                        /* 找到节点p,替换value值 */
                        if ((r = t.root) != null &&
                            (p = r.findTreeNode(h, key, null)) != null)
                            val = p.val;
                        /* 若 p为 null && val 不为null,添加新节点 */    
                        else if ((val = mappingFunction.apply(key)) != null) {
                            added = true;
                            t.putTreeVal(h, key, val);
                        }
                    }
                }
            }
            if (binCount != 0) {
            	/* 元素个数 > 树化默认值= 8,进行树化操作 */
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                /* 若未发生添加操作,返回 val */    
                if (!added)
                    return val;
                break;
            }
        }
    }
    /* 执行到这里代表 added 为true,val 不为null代表新添加了一个节点 */
    if (val != null)
        addCount(1L, binCount);
    return val;
}



5. computeIfPresent

  • 给定 key 值找到节点 p,与 remappingFunction(key,value) 生成的 val 值

    • p 为 null :不进行任何操作
    • p 不为 null,val 为null :删除 p 节点
    • p 不为 null,val 不为null :替换 p 节点的 value 值
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
	/* null 异常检测 */
    if (key == null || remappingFunction == null)
        throw new NullPointerException();
    int h = spread(key.hashCode()); // 获取 hash 值
    V val = null;
    int delta = 0;
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        /* tab 未初始化 */
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        /* 当前桶位为空,直接退出 */    
        else if ((f = tabAt(tab, i = (n - 1) & h)) == null)
            break;
        /* 当前tab正在扩容,先帮助扩容 */    
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        else {
            synchronized (f) {
            	/* 锁住节点后判断 首节点f 有没有被修改 */
                if (tabAt(tab, i) == f) {
                	/* 链表节点 */
                    if (fh >= 0) {
                        binCount = 1;
                        for (Node<K,V> e = f, pred = null;; ++binCount) {
                            K ek;
                            /* 找到 key 对应的节点 */
                            if (e.hash == h &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
                                val = remappingFunction.apply(key, e.val);
                                /* val 不为null,替换 value 值,若为null,删除该节点 */
                                if (val != null)
                                    e.val = val;
                                else {
                                    delta = -1;
                                    Node<K,V> en = e.next;
                                    if (pred != null)
                                        pred.next = en;
                                    else
                                        setTabAt(tab, i, en);
                                }
                                break;
                            }
                            pred = e;
                            if ((e = e.next) == null)
                                break;
                        }
                    }
                    /* 树节点 */
                    else if (f instanceof TreeBin) {
                        binCount = 2;
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> r, p;
                        /* 找到 key 对应的节点 */
                        if ((r = t.root) != null &&
                            (p = r.findTreeNode(h, key, null)) != null) {
                            val = remappingFunction.apply(key, p.val);
                            /* val 不为null,替换 value 值,若为null,删除该节点 */
                            if (val != null)
                                p.val = val;
                            else {
                                delta = -1;
                                if (t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                }
            }
            if (binCount != 0)
                break;
        }
    }
    /* 发生了删除操作,count进行相应的计数 */
    if (delta != 0)
        addCount((long)delta, binCount);
    return val;
}



6. 小总结

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapTest03 {
    public static void main(String[] args) throws Exception {
        ConcurrentHashMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        for(int i = 1; i <= 10; i++) {
            concurrentHashMap.put(i, i);
        }
        System.out.println("now concurrentHashMap: " + concurrentHashMap);
        System.out.println("concurrentHashMap.get(1): " + concurrentHashMap.get(1));
        System.out.println("concurrentHashMap.get(11): " + concurrentHashMap.get(11));
        System.out.println("concurrentHashMap.getOrDefault(1, 10): " + concurrentHashMap.getOrDefault(1, 10));
        System.out.println("concurrentHashMap.getOrDefault(11, 11): " + concurrentHashMap.getOrDefault(11, 11));
        System.out.println("now concurrentHashMap: " + concurrentHashMap);
        System.out.println("=================== compute =======================");
        System.out.println("concurrentHashMap.compute(1, (key, value) -> value * 10): " + concurrentHashMap.compute(1, (key, value) -> value * 10));
        System.out.println("concurrentHashMap.compute(2, (key, value) -> null): " + concurrentHashMap.compute(2, (key, value) -> null));
        /* 这里很坑爹,因为当前桶位为空时,执行的是 val = remappingFunction.apply(key, null)) != null
         * 可以看到value值出变成null,即当使用value值进行操作时,会报 null 异常 */
        System.out.println("concurrentHashMap.compute(11, (key, value) -> 110): " + concurrentHashMap.compute(11, (key, value) -> 110));
        System.out.println("concurrentHashMap.compute(12, (key, value) -> null): " + concurrentHashMap.compute(12, (key, value) -> null));
        System.out.println("now concurrentHashMap: " + concurrentHashMap);
        System.out.println("=================== computeIfAbsent =======================");
        System.out.println("concurrentHashMap.computeIfAbsent(3, (key) -> 30): " + concurrentHashMap.computeIfAbsent(3, (key) -> 30));
        System.out.println("concurrentHashMap.computeIfAbsent(4, (key) -> null): " + concurrentHashMap.computeIfAbsent(4, (key) -> null));
        System.out.println("concurrentHashMap.computeIfAbsent(13, (key) -> 130): " + concurrentHashMap.computeIfAbsent(13, (key) -> 130));
        System.out.println("concurrentHashMap.computeIfAbsent(14, (key) -> null): " + concurrentHashMap.computeIfAbsent(14, (key) -> null));
        System.out.println("now concurrentHashMap: " + concurrentHashMap);
        System.out.println("=================== computeIfPresent =======================");
        System.out.println("concurrentHashMap.computeIfPresent(5, (key, value) -> value * 10): " + concurrentHashMap.computeIfPresent(5 (key, value) -> value * 10));
        System.out.println("concurrentHashMap.computeIfPresent(6, (key, value) -> null): " + concurrentHashMap.computeIfPresent(6, (key, value) -> null));
        System.out.println("concurrentHashMap.computeIfPresent(15, (key, value) -> value * 10): " + concurrentHashMap.computeIfPresent(15, (key, value) -> value * 10));
        System.out.println("concurrentHashMap.computeIfPresent(16, (key, value) -> null): " + concurrentHashMap.computeIfPresent(16, (key, value) -> null));
        System.out.println("now concurrentHashMap: " + concurrentHashMap);
    }
}

在这里插入图片描述



版权声明:本文为weixin_44245828原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。