java并发编程实战wwj----------第三阶段-------------ConcurrentHashMap----------------72

阻塞队列:多个线程操作的队列。

JDK7:分成若干哥Segments。

是一个key和value数组。

原理:https://blog.csdn.net/it_dx/article/details/77941538

我们看get的方法。

get:

public V get(Object key) {
        Segment<K,V> s; 
        HashEntry<K,V>[] tab;
        //根据key的值计算hash值
        int h = hash(key);
        //获得segment的index  
        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
        //保证拿到的是最新的
        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && 
 //通过hash值定位segment中对应的HashEntry 遍历HashEntry,
如果key存在,返回key对应的value 如果不存在则返回null
            (tab = s.table) != null) {
            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
                 e != null; e = e.next) {
                K k;
                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
                    return e.value;
            }
        }
        return null;
    }

put:

public V put(K key, V value) {
        Segment<K,V> s;
        //键和值都不能为空
        if (value == null)
            throw new NullPointerException();
        //计算key的hash值
        int hash = hash(key);
        //获得key所属的segemngt
        int j = (hash >>> segmentShift) & segmentMask;
        if ((s = (Segment<K,V>)UNSAFE.getObject          
             (segments, (j << SSHIFT) + SBASE)) == null)
            //初试化segment(懒加载模式)
            s = ensureSegment(j);
        return s.put(key, hash, value, false);
    }
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
//获取锁,保证线程安全
            HashEntry<K,V> node = tryLock() ? null :
                scanAndLockForPut(key, hash, value);
            V oldValue;
            try {
                HashEntry<K,V>[] tab = table;

                int index = (tab.length - 1) & hash;
                HashEntry<K,V> first = entryAt(tab, index);  //定位到具体的HashEntry
                for (HashEntry<K,V> e = first;;) { //3
                    if (e != null) {
                        K k;
                        if ((k = e.key) == key ||
                            (e.hash == hash && key.equals(k))) {
                            oldValue = e.value;
                            //覆盖旧值
                            if (!onlyIfAbsent) {
                                e.value = value;
                                ++modCount;
                            }
                            break;
                        }
                        e = e.next;
                    }
                    else {
                        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;
        }

size:

public int size() {
        final Segment<K,V>[] segments = this.segments;
        int size;
        boolean overflow; 
        long sum;         
        long last = 0L;   
        int retries = -1; 
        try {
            for (;;) {
            //RETRIES_BEFORE_LOCK为不变常量2 尝试两次不锁住Segment的方式来统计每个Segment的大小,如果在统计的过程中Segment的count发生变化,这时候再加锁统计Segment的count
                if (retries++ == RETRIES_BEFORE_LOCK) {  //加锁
                    for (int j = 0; j < segments.length; ++j)
                        ensureSegment(j).lock(); 
                }
                sum = 0L;
                size = 0;
                overflow = false;
                for (int j = 0; j < segments.length; ++j) {
                    Segment<K,V> seg = segmentAt(segments, j);
                    if (seg != null) {
                        sum += seg.modCount;  //2
                        int c = seg.count;
                        if (c < 0 || (size += c) < 0)
                            overflow = true;
                    }
                }
                if (sum == last)
                    break;
                last = sum;
            }
        } finally {
            if (retries > RETRIES_BEFORE_LOCK) {
                for (int j = 0; j < segments.length; ++j)
                    segmentAt(segments, j).unlock();
            }
        }
        return overflow ? Integer.MAX_VALUE : size;
    }

我总结一个重要的知识点:

通过key的hash再位移值获得key所属的segment,segment.put中通过key的hash值再(tab.length - 1) & hash获取index定位到是哪个hashEntry。遍历hashEntry。

判断hashEntry是不是存在这个值:

1.通过key,1不成立的话就是2.节点的hash==key的hash&&节点的key去equals输入的key。

put的话就是如果通过key的hash再(tab.length - 1) & hash去定位HashEntry有值了,就加个链表节点,节点的key就是元素的hash值,并且节点的key要equals元素的key。

----------------------------------

发布了322 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_28764557/article/details/104502879