• Java集合:ConcurrentHashMap


    一、引入背景(Why)

    1. 在多线程环境下,HashMap的put会导致扩容,扩容引起死循环,导致CPU使用率100%

    2. 可以使用HashTable和Collections.synchronizedMap(hashMap)可以解决多线程的问题

    3. HashTable和Collections.synchronizedMap(hashMap)对读写进行加一个全局锁,一个线程读写map的元素,其余线程必须等待,性能不好

    4. ConcurrentHashMap也加了锁,但是只锁了map的一部分,其余线程可以继续读写没锁住的部分,优化了操作性能

    二、JDK1.7的实现(了解):Segment分段锁+HashEntry+ReentrantLock

    1. HashEntry是键值对,用来存储数据

    2. 桶是由若干个HashEntry连接起来的链表

    3. Segment分段锁继承ReentrantLock,每个Segment对象锁住若干个桶

    4. 一个ConcurrentHashMap实例中,包含由若干个Segment对象组成的数组

    5. HashEntry->HashBucket->Segment->ConcurrentHashMap,一层一层被包含

    三、JDK1.8的实现(理解):Node+CAS+Synchronized,锁的粒度更小

    1. 数据结构:抛弃了臃肿的Segment分段锁机制,采用CAS+Synchronized来保证并发更新的安全,底层依然是数组+链表+红黑树的存储结构

    2. table,默认为16大小的数组,第一次put值才会初始化

    3. Node,保存key-value,hash值和下一个node地址

    class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        volatile V val;  //volatile保证并发的可见性
        volatile Node<K,V> next;  //volatile保证并发的可见性
    }

    4. put实现,采用CAS+Synchronized实现并发插入或者更新,当链表长度大于8,会把链表转为红黑树

    final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            ...省略部分代码
        }
        addCount(1L, binCount);
        return null;
    }

    5. size实现:使用一个volatile类型的变量baseCount记录元素个数,通过addCount()更新

    6. 扩容,数组使用volatile修饰,表示数组的地址是volatile,而不是表示数据元素是volatile,在扩容的时候,对其他线程保持可见性

    7. get操作,源码没有加锁,因为Node的值和指针,使用volatile修饰的

    8. JDK1.8的ConcurrentHashMap存在bug,会进入死循环,1.9修复了

    四、红黑树的实现分析

    1. 红黑树是一种特殊的二叉树

    2. 主要用来存储有序的数据

    3. 可以高效检索,时间复杂度为O(lgn)

    参考:

    https://www.jianshu.com/p/c0642afe03e0

    https://www.jianshu.com/p/f6730d5784ad

    https://www.jianshu.com/p/23b84ba9a498

    https://www.jianshu.com/p/e694f1e868ec

  • 相关阅读:
    Dolby pro logic introduction
    3.8 Language Support(audio)
    what is dual mono
    会计misc
    除权除息
    MPEG2-TS音视频同步原理(PCR dts pts)
    计算视频文件(包含PCR)播放带宽的方法 PCR计算码率
    cocos2d 动作切换
    cocos2d 播放音乐
    cocos2d 主角更随触屏走
  • 原文地址:https://www.cnblogs.com/june0816/p/7295736.html
Copyright © 2020-2023  润新知