线程安全的Map之Hashtable & ConcurrentHashMap——java技术栈系列文章

IT黑名单 2017-3-2 11:13:13

目录

Hashtable

Hashtable.java

public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }
    ...
    int hash = key.hashCode();
    ...
}
       从源码可以看出,Hashtable是基于synchronized支持线程安全,并且不允许key和value为null。synchronized操作的,所以Hashtable的写操作慢。其它的基本类似于HashMap。

ConcurrentHashMap

        ConcurrentHashMap引入了分段锁的概念,即把map的数组拆成N段(1.6/1.7中的Segment),put/get时根据hashCode算出在哪段,然后方法内加synchronized锁,这样在实现线程安全的基础上,相较HashTable的全数组锁,效率提升N倍(默认为16,segments默认为初始长度16的数组)。JDK8中对ConcurrentHashMap做了较大调整,以下部分如无兴趣可以略过

ConcurrentHashMap.java jdk1.6

public V put(K key, V value) {
    ...
    return segmentFor(hash).put(key, hash, value, false); //segmentFor(int hash)根据hash返回所属的Segment
}

static final class Segment<K,V> extends ReentrantLock implements Serializable {
    V put(K key, int hash, V value, boolean onlyIfAbsent) {
        lock(); //锁Segment
        try {
            ...//执行业务逻辑
        } finally {
            unlock(); //解锁Segment
        }
    }
}

ConcurrentHashMap.java jdk1.7

public V put(K paramK, V paramV){
    ...
    int i = hash(paramK);
    int j = i >>> this.segmentShift & this.segmentMask;
    Segment localSegment;
    if ((localSegment = (Segment)UNSAFE.getObject(this.segments, (j << SSHIFT) + SBASE)) == null)
        localSegment = ensureSegment(j);
    return localSegment.put(paramK, i, paramV, false);//localSegment执行put
}

static final class Segment<K, V> extends ReentrantLock implements Serializable{
    // put方法内加锁
    final V put(K paramK, int paramInt, V paramV, boolean paramBoolean) {
        ConcurrentHashMap.HashEntry localHashEntry1 = tryLock() ? null : scanAndLockForPut(paramK, paramInt, paramV);
        ...
        label218: unlock();
        return localObject1; 
    }
}

ConcurrentHashMap.java jdk1.8

public V put(K key, V value) {
    return putVal(key, value, false);
}

transient volatile Node<K,V>[] table; // table对象volatile修饰
final V putVal(K key, V value, boolean onlyIfAbsent) {
    ...
    for (Node<K,V>[] tab = table;;) { //一直循环知道无其它进程修改table
        ...
        // int n = tab.length
        // Node<K,V> f = tabAt(tab, i = (n - 1) & hash)
        synchronized (f) { //synchronized锁f 即锁table[i] 跟1.6 1.7中锁Segment异曲同工
            ...// 业务逻辑
        }
    }
    return xx;
}


转载请注明来源【IT黑名单

本文链接:http://blog.itblacklist.cn/20170302/8445.html

© Copyright 2016 IT黑名单 Inc.All Rights Reserved. 豫ICP备15018592号-2