ConcurrentHashMap

来源:互联网 发布:织梦cms如何仿站 编辑:程序博客网 时间:2024/06/07 06:59
ConcurrentHashMap:重要:1)ConcurrentHashMap使用了多个锁来控制对hash表的不同段(Segment)进行修改(即锁分离技术),每个段其实就是一个小的 hash table,它们都有自己各自的的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。2)Segment锁是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色。3)一个ConcurrentHashMap里包含一个Segment数组,Segment的结构其实就是一个小的hash table。一个Segment里包含一个HashEntry数组,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。4)ConcurrentHashMap中Segment的数量一经指定,不可改变。如果需要扩容,那么只会对Segment中的链表数组进行扩容,所以扩容过程不需要对整个ConcurrentHashMap做rehash,而只需要对Segment里面的元素做一次rehash就可以了。--------------------1)get方法:特点:简单和高效。首先调用传入的Key的hashCode()方法,返回的hashCode用于找到对应的segment的位置,然后调用Segment的get(key, hash)方法,通过哈希算法找到对应的元素public V get(Object key) {int hash = hash(key.hashCode());return segmentFor(hash).get(key, hash);}高效:整个get过程不需要加锁(注:当值为null时,才会加锁去读)原因:get方法中将共享变量都定义成volatile,例如:用于统计当前Segement大小的count字段和用于存储值的HashEntry的value2)put方法:首先调用key的hashCode()方法,返回的hashCode用于找到对应的segment的位置,然后调用Segment的put()方法来储存Entry对象重要:1)多线程环境下,对共享变量进行写入操作时必须得加锁。2)Segment的put方法中使用了可重入锁。    public V put(K key, V value) {        if (value == null)            throw new NullPointerException();        int hash = hash(key.hashCode());        return segmentFor(hash).put(key, hash, value, false);    }3)size方法:1)ConcurrentHashMap的大小就是全部Segment的count之和。2)在累加count的过程中,已经累加过的count发生变化的几率很小,3)ConcurrentHashMap先以不锁住Segment的方式来统计各个Segment的大小,以这样的方式统计2次,如果2次统计的count不一致,则再采用加锁的方式来统计所有Segment的大小。4)ConcurrentHashMap使用modCount变量,在put、remove和clean方法中操作元素前都会将modCount加1,比较modCount的值在统计前后是否一致来判断segment的大小是否发生变化。// ConcurrentHashMap部分源码(jdk1.6)public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable {    final Segment<K,V>[] segments;    transient Set<K> keySet;    transient Set<Map.Entry<K,V>> entrySet;    transient Collection<V> values;    static final class Segment<K,V> extends ReentrantLock implements Serializable {transient volatile HashEntry<K,V>[] table;// 当前Segement的大小,即包含HashEntry的数量        transient volatile int count;// table被更新的次数。注:在put、remove和clean方法中操作元素前都会将modCount加1transient int modCount;// ...}    static final class HashEntry<K,V> {        final K key;        final int hash;        volatile V value;        final HashEntry<K,V> next;        HashEntry(K key, int hash, HashEntry<K,V> next, V value) {            this.key = key;            this.hash = hash;            this.next = next;            this.value = value;        }// ...    }    public V get(Object key) {        int hash = hash(key.hashCode());        return segmentFor(hash).get(key, hash);    }    public V put(K key, V value) {        if (value == null)            throw new NullPointerException();        int hash = hash(key.hashCode());        return segmentFor(hash).put(key, hash, value, false);    }}

0 0