jdk源码ConcurrentHashMap——jdk1.7

 首先做个分析:

hashMap,hashTable,ConcurrentHashMap,这三者之间的区别,HashMap是线程不安全的,在多线程的环境下,hashMap的put方法可能引起死循环,于是为了线程安全,出现了hashTable,hashTable解决多线程安全的问题是简单粗暴的加synchronized关键字,但是这种方法引起效率低下,于是ConcurrentHashMap出现了,下面主要介绍下ConcurrentHashMap。

 

ConcurrentHashMap实现的接口是ConcurrentMap

public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
        implements ConcurrentMap<K, V>, Serializable {

 成员变量,这里只列举出了ConcurrentHashMap特有的

   static final int DEFAULT_CONCURRENCY_LEVEL = 16; //初始的并发等级,通过并发等级来确定Segment的大小

   static final int MIN_SEGMENT_TABLE_CAPACITY = 2;// segment的最小值

    static final int MAX_SEGMENTS = 1 << 16; //segment的最大值

 ConcurrentHashMap的构造函数

 public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel) {
        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
        if (concurrencyLevel > MAX_SEGMENTS)
            concurrencyLevel = MAX_SEGMENTS;
        // Find power-of-two sizes best matching arguments
        int sshift = 0;//计算ssize左移的次数
        int ssize = 1;//计算segment的大小
        while (ssize < concurrencyLevel) {//segment的大小为2^n
            ++sshift;
            ssize <<= 1;
        }
        this.segmentShift = 32 - sshift;
        this.segmentMask = ssize - 1;//这个为什么要为Segment数组的长度 -1,主要是为了让低位为1,这样在做&运算确定Segment的索引时能够更加分散
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        int c = initialCapacity / ssize;//计算每个segment的大小
        if (c * ssize < initialCapacity)//若是条件成立,表示c有余数,所以增加一个segment
            ++c;
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        while (cap < c)
            cap <<= 1;
        // create segments and segments[0]//创建一个segment,并且放在 segment[ 0]
        Segment<K,V> s0 =
            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                             (HashEntry<K,V>[])new HashEntry[cap]);
        Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
        this.segments = ss;
    } 

Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
            this.loadFactor = lf;
            this.threshold = threshold;
            this.table = tab;
        } 

看完ConcurrentHashMap的构造函数,我们应该对该map的数据结构有个大致了解,如下:

 

 

 put方法,首先对key值第一次hash确定segment的位置,然后在segment内部获取锁,接着key第二次hash,确定hashEntry在table中的位置,然后put操作和hashMap相同,最后关闭锁

 public V put(K key, V value) {//找到对应的segment,吧key,value放入对应的segment中
        Segment<K,V> s;
        if (value == null)
            throw new NullPointerException();
        int hash = hash(key);
        int j = (hash >>> segmentShift) & segmentMask;
        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
            s = ensureSegment(j);
        return s.put(key, hash, value, false);
    }

 final V put(K key, int hash, V value, boolean onlyIfAbsent) {

//每个segment进行put操作的时候都要进行加锁操作
            HashEntry<K,V> node = tryLock() ? null :
                scanAndLockForPut(key, hash, value);
            V oldValue;
            try {
                HashEntry<K,V>[] tab = table;//table为segment所连接的hashEntry数组,
                int index = (tab.length - 1) & hash;
                HashEntry<K,V> first = entryAt(tab, index);//找到数组对应下标的链表
                for (HashEntry<K,V> e = first;;) {
                    if (e != null) {//头结点不为空
                        K k;
                        if ((k = e.key) == key ||
                            (e.hash == hash && key.equals(k))) {//若是key相同则替换
                            oldValue = e.value;
                            if (!onlyIfAbsent) {
                                e.value = value;
                                ++modCount;
                            }
                            break;
                        }
                        e = e.next;
                    }
                    else {//把当前node插入到table[i]的位置
                        if (node != null)
                            node.setNext(first);
                        else
                            node = new HashEntry<K,V>(hash, key, value, first);
                        int c = count + 1;
                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
                            rehash(node);
                        else
                            setEntryAt(tab, index, node);
                        ++modCount;
                        count = c;
                        oldValue = null;
                        break;
                    }
                }
            } finally {
                unlock();
            }
            return oldValue;
        } 

remove()操作

public V remove(Object key) {
        int hash = hash(key);
        Segment<K,V> s = segmentForHash(hash);//找到对应的segment
        return s == null ? null : s.remove(key, hash, null);
    }

    final V remove(Object key, int hash, Object value) {
            if (!tryLock())//获取锁
                scanAndLock(key, hash);
            V oldValue = null;
            try {
                HashEntry<K,V>[] tab = table;//table是segment所连接的hashEntrt数组
                int index = (tab.length - 1) & hash;
                HashEntry<K,V> e = entryAt(tab, index);//找到链表头
                HashEntry<K,V> pred = null;//记录删除节点的前一节点
                while (e != null) {
                    K k;
                    HashEntry<K,V> next = e.next;
                    if ((k = e.key) == key ||
                        (e.hash == hash && key.equals(k))) {
                        V v = e.value;
                        if (value == null || value == v || value.equals(v)) {
                            if (pred == null)//删除头结点
                                setEntryAt(tab, index, next);
                            else
                                pred.setNext(next);
                            ++modCount;
                            --count;
                            oldValue = v;
                        }
                        break;
                    }
                    pred = e;
                    e = next;
                }
            } finally {
                unlock();
            }
            return oldValue;
        }

posted on 2018-09-28 14:16  计科wang  阅读(294)  评论(0编辑  收藏  举报