Concurrent包中ConcurrentHashMap

自从jdk1.5之后,JDK增加了ConcurrentMap接口,这个接口是对应的 java.util.Map并发集合,提供了putIfAbsent, remove,replace三个接口方法,concurrent包也提供了ConcurrentMap的实现类ConcurrentHashMap:

首先说一下ConcurrentHashMap的实现方式:
相比线程安全的HashTable各种方法都加了同步方法,ConcurrentHashMap进行了相应的改进。首先将整个table分成了多个Segment,默认为16个

 public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel) {
        //...
        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存储的方式仍然为HashEntry,

   Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
            //...
        }

内部操作也都是使用的tryLock,

 final V put(K key, int hash, V value, boolean onlyIfAbsent) {
            HashEntry<K,V> node = tryLock() ? null :
                scanAndLockForPut(key, hash, value);
            V oldValue;
            try {
               //...
            } finally {
                unlock();
            }
            return oldValue;
        }

   final V remove(Object key, int hash, Object value) {
            if (!tryLock())
                scanAndLock(key, hash);
            V oldValue = null;
            try {
               //...
            } finally {
                unlock();
            }
            return oldValue;
        }

  这样看来这个Segment相当于小的HashTable,也就是说ConcurrentHashMap将HashTable在操作上锁定由全表锁定变成了部分锁定的方式增加了并发访问。但是有别于HashTable所有操作都是使用了同步synchronize,ConcurrentHashMap在get,clear,values方法中并没有使用同步方法,这里也就体现了ConcurrentHashMap的弱一致性。

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

     public void clear() {
        final Segment<K,V>[] segments = this.segments;
        for (int j = 0; j < segments.length; ++j) {
            Segment<K,V> s = segmentAt(segments, j);
            if (s != null)
                s.clear();
                //虽然Segment是使用的lock,但是当一个Segment被clear后,
                //另一个正在clear时,原先被clear的有可能又被添加了数据
        }
    }

    public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null) ? vs : (values = new Values());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值