1.7ConcurrentHashMap

 

 

 

使用锁分段技术,利用Segment实现分段锁,每个Segment包含table

transient volatile HashEntry<K,V>[] table;

对于put使用tryLock() 加锁保证并发安全性。对于get无需加锁因为

使用了volatile替换了synchronized。提供了线程间的可见性,

对于key这是使用final变量表示,以不变行保证了线程的安全。

 

 /**

     * ConcurrentHashMap list entry. Note that this is never exported

     * out as a user-visible Map.Entry.

     */

    static final class HashEntry<K,V> {

        final int hash;

        final K key;

        volatile V value;

        volatile HashEntry<K,V> next;

 

        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {

            this.hash = hash;

            this.key = key;

            this.value = value;

            this.next = next;

        }

 

        /**

         * Sets next field with volatile write semantics.  (See above

         * about use of putOrderedObject.)

         */

        final void setNext(HashEntry<K,V> n) {

            UNSAFE.putOrderedObject(this, nextOffset, n);

        }

 

        // Unsafe mechanics

        static final sun.misc.Unsafe UNSAFE;

        static final long nextOffset;

        static {

            try {

                UNSAFE = sun.misc.Unsafe.getUnsafe();

                Class k = HashEntry.class;

                nextOffset = UNSAFE.objectFieldOffset

                    (k.getDeclaredField("next"));

            } catch (Exception e) {

                throw new Error(e);

            }

        }

    }

 

 

一:Init 初始化的时候默认生成一个16长度的Segment结构。

Segment中默认生成size2的两个HashEntry

 

       

 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];

 

 

二:put操作:首先对key进行hash,然后使用

int j = (hash >>> segmentShift) & segmentMask;计算出了所在的segment

之后放到该segmenttable,其中tableHashEntry

public V put(K key, V value) {

        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);

    }

 

使用tryLock() 加锁保证并发安全性。

 

 

 

 

三:get操作:和put类似的hash方法,对key进行hash一次,

之后根据hash值通过(((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;

计算出所在的segment;获得对应的table

无需加锁。

 public V get(Object key) {

        Segment<K,V> s; // manually integrate access methods to reduce overhead

        HashEntry<K,V>[] tab;

        int h = hash(key);

        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;

        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != 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;

    }

 

  无需加锁因为使用了volatile替换了synchronized

提供了线程间的可见性,对于key这是使用final变量表示,

以不变行保证了线程的安全。

 

 

 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);

                for (HashEntry<K,V> e = first;;) {

                    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操作:使用segment中的count属性来统计,

为了让统计性能更高,先尝试两次获取的modCount是否一致,

一致的话说明累加count的时候没修改被统计的segment

无需加锁即可得到合计的size,否则加锁。

 public int size() {

        // Try a few times to get accurate count. On failure due to

        // continuous async changes in table, resort to locking.

        final Segment<K,V>[] segments = this.segments;

        int size;

        boolean overflow; // true if size overflows 32 bits

        long sum;         // sum of modCounts

        long last = 0L;   // previous sum

        int retries = -1; // first iteration isn't retry

        try {

            for (;;) {

                if (retries++ == RETRIES_BEFORE_LOCK) {

                    for (int j = 0; j < segments.length; ++j)

                        ensureSegment(j).lock(); // force creation

                }

                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;

                        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;

    }

 

 

67区别是不是volatile的;不清楚7不是volatile如何保证线程间的可见性?

因为保证访问该变量的时候都是加了lock或者将segment变为volatile保证其可见性。  jdk7的注释如下:)

    /**

         * The number of elements. Accessed only either within locks

         * or among other volatile reads that maintain visibility.

         */

        transient int count;

 

 

 @SuppressWarnings("unchecked")

    static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {

        long u = (j << SSHIFT) + SBASE;

        return ss == null ? null :

            (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);

    }

 

 

 

 

 







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值