zoukankan      html  css  js  c++  java
  • 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;
            }

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/wanglingdeboke/p/9718277.html
Copyright © 2011-2022 走看看