• 并发容器 concurrentHashMap--1.7 更改


    1.6的解释已经很多了,昨天本来做好的文章就不忍拿出来献丑了

    这篇链接就不错 http://www.infoq.com/cn/articles/ConcurrentHashMap  

    本文就简单叙述1.7的更改部分.

    1:最明显的,采用了尝试自旋锁的机制(多核情况下尝试自旋64次(ps:put的时候,自旋会预创建),还是不行再锁)

    典型代码

    private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
                HashEntry<K,V> first = entryForHash(this, hash);
                HashEntry<K,V> e = first;
                HashEntry<K,V> node = null;
                int retries = -1; // negative while locating node
                while (!tryLock()) {
                    HashEntry<K,V> f; // to recheck first below
                    if (retries < 0) {
                        if (e == null) {
                            if (node == null) // speculatively create node
                                node = new HashEntry<K,V>(hash, key, value, null);
                            retries = 0;
                        }
                        else if (key.equals(e.key))
                            retries = 0;
                        else
                            e = e.next;
                    }
                    else if (++retries > MAX_SCAN_RETRIES) {
                        lock();
                        break;
                    }
                    else if ((retries & 1) == 0 &&
                             (f = entryForHash(this, hash)) != first) {
                        e = first = f; // re-traverse if entry changed
                        retries = -1;
                    }
                }
                return node;
            }

    2:解决了弱一致性的问题,1.6使用volatile类型的数组,改变数组元素的值是直接操作数组,在并发中存在一致性问题,到1.7变为UNSAFE.getObjectVolatile和UNSAFE.putOrderedObject

    典型代码

     1     public V get(Object key) {
     2         Segment<K,V> s; // manually integrate access methods to reduce overhead
     3         HashEntry<K,V>[] tab;
     4         int h = hash(key);
     5         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
     6         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
     7             (tab = s.table) != null) {
     8             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
     9                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
    10                  e != null; e = e.next) {
    11                 K k;
    12                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
    13                     return e.value;
    14             }
    15         }
    16         return null;
    17     }

    3:remove和rehash操作优化,优化思路暂时没研究,但remove方法现在不需要拷贝remove前的数据了---待补充

    remove代码

     final V remove(Object key, int hash, Object value) {
                if (!tryLock())
                    scanAndLock(key, hash);
                V oldValue = null;
                try {
                    HashEntry<K,V>[] tab = table;
                    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;
            }

    rehash代码

     private void rehash(HashEntry<K,V> node) {
                /*
                 * Reclassify nodes in each list to new table.  Because we
                 * are using power-of-two expansion, the elements from
                 * each bin must either stay at same index, or move with a
                 * power of two offset. We eliminate unnecessary node
                 * creation by catching cases where old nodes can be
                 * reused because their next fields won't change.
                 * Statistically, at the default threshold, only about
                 * one-sixth of them need cloning when a table
                 * doubles. The nodes they replace will be garbage
                 * collectable as soon as they are no longer referenced by
                 * any reader thread that may be in the midst of
                 * concurrently traversing table. Entry accesses use plain
                 * array indexing because they are followed by volatile
                 * table write.
                 */
                HashEntry<K,V>[] oldTable = table;
                int oldCapacity = oldTable.length;
                int newCapacity = oldCapacity << 1;
                threshold = (int)(newCapacity * loadFactor);
                HashEntry<K,V>[] newTable =
                    (HashEntry<K,V>[]) new HashEntry[newCapacity];
                int sizeMask = newCapacity - 1;
                for (int i = 0; i < oldCapacity ; i++) {
                    HashEntry<K,V> e = oldTable[i];
                    if (e != null) {
                        HashEntry<K,V> next = e.next;
                        int idx = e.hash & sizeMask;
                        if (next == null)   //  Single node on list
                            newTable[idx] = e;
                        else { // Reuse consecutive sequence at same slot
                            HashEntry<K,V> lastRun = e;
                            int lastIdx = idx;
                            for (HashEntry<K,V> last = next;
                                 last != null;
                                 last = last.next) {
                                int k = last.hash & sizeMask;
                                if (k != lastIdx) {
                                    lastIdx = k;
                                    lastRun = last;
                                }
                            }
                            newTable[lastIdx] = lastRun;
                            // Clone remaining nodes
                            for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
                                V v = p.value;
                                int h = p.hash;
                                int k = h & sizeMask;
                                HashEntry<K,V> n = newTable[k];
                                newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
                            }
                        }
                    }
                }
                int nodeIndex = node.hash & sizeMask; // add the new node
                node.setNext(newTable[nodeIndex]);
                newTable[nodeIndex] = node;
                table = newTable;
            }

    4:增加了replace方法:如果key不存在,则直接返回false ,而非执行插入操作

     final boolean replace(K key, int hash, V oldValue, V newValue) {
                if (!tryLock())
                    scanAndLock(key, hash);
                boolean replaced = false;
                try {
                    HashEntry<K,V> e;
                    for (e = entryForHash(this, hash); e != null; e = e.next) {
                        K k;
                        if ((k = e.key) == key ||
                            (e.hash == hash && key.equals(k))) {
                            if (oldValue.equals(e.value)) {
                                e.value = newValue;
                                ++modCount;
                                replaced = true;
                            }
                            break;
                        }
                    }
                } finally {
                    unlock();
                }
                return replaced;
            }
  • 相关阅读:
    微信“为盲胞读书”项目上线“团体领读”新功能
    神秘代码让iPhone微信闪退的解决方法
    [腾讯首季业绩数据]微信支付用户数持续上升
    [民间调查]小学生微信使用情况的调查 90%小学高年级学生用微信
    O2O模式成功案例分享 汲取精华化为己用
    太原警方通过微博提醒您手机丢失如何保微信安全
    百度富媒体展示允许自定义站点Logo/简介等
    网页出现scanstyles does nothing in Webkit / Mozilla的解决方法
    安卓微信新版内测 可分享小视频/可设微信字体大小
    微信电脑版微信1.1 for Windows更新 可@人/转发撤回消息/可播小视频
  • 原文地址:https://www.cnblogs.com/duchanggang/p/4638825.html
Copyright © 2020-2023  润新知