JDK7中ConcurrentHashMap源码解析

1. hashMap中扩容

transfer时可能出现循环链表问题

1. 使用头插法

hashMap是并发不安全的,hashTable是并发安全,使用synchronized保证线程安全。

hashTable保证线程安全的put方法实例:

        public synchronized V put(K key, V value) {

void addEntry(int hash, K key, V value, int bucketIndex) {
//如果hashMap大小大于等于阈值并且数据元素不为空扩容       
if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);//计算数组下标位置
        }

        createEntry(hash, key, value, bucketIndex);
    }

//扩容
void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        //将老数组元素放入新数组
        transfer(newTable, initHashSeedAsNeeded(newCapacity));
        table = newTable;
        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    }

//转移老数组元素,双重循环遍历数组和链表
void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e : table) {
            while(null != e) {
                Entry<K,V> next = e.next;
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            }
        }
    }

1.1 get() (TODO)

1.2 remove问题

remove最后一个时报错:Exception in thread "main"java.util.ConcurrentModificationException

解决方法:调用迭代器的remove方法

错误发生原因:调用map.remove(key)方法时modCount会++于是在调用hashmap的nextEntry()时报错。

if (modCount != expectedModCount)

        throw new ConcurrentModificationException();

而解决方法使用迭代器remove方法时hashmap会重新赋值

expectedModCount = modCount;
import java.util.HashMap;
import java.util.Iterator;

public class HashMapTest {

    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("1","1");
        map.put("2","2");

//        for(String key:map.keySet()){
//            if("1".equals(key)){
//                map.remove(key);
//            }
//        }

//        for(String key:map.keySet()){
//            if(key.equals("2")){
//                map.remove(key);//Exception in thread "main" java.util.ConcurrentModificationException
//            }
//        }

        //上述代码编译后代码
        Iterator i$ = map.keySet().iterator();

        while(i$.hasNext()) {
            String key = (String)i$.next();
            if (key.equals("2")) {
//                map.remove(key);//Exception in thread "main" java.util.ConcurrentModificationException
                //解决方法调用iterator的remove方法
                i$.remove();
            }
        }


    }
}

2. jdk7-cocurrentHashMap

cocurrentHashMap采用分段思想,segment,里面会有一个一个的hashEntry数组组成,segment继承reentrantLock,所以只能保证线程安全的。

2.1 构造方法

DEFAULT_INITIAL_CAPACITY:默认初始大小16
DEFAULT_LOAD_FACTOR:0.75f,作为一个计算系数吧!
DEFAULT_CONCURRENCY_LEVEL:并发级别,默认16
public ConcurrentHashMap() {
    this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
}
public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel) {
        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
        if (concurrencyLevel > MAX_SEGMENTS)
            concurrencyLevel = MAX_SEGMENTS;
        // Find power-of-two sizes best matching arguments
        int sshift = 0;
        int ssize = 1;
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
        this.segmentShift = 32 - sshift;
        this.segmentMask = ssize - 1;
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        int c = initialCapacity / ssize;
        if (c * ssize < initialCapacity)
            ++c;
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        while (cap < c)
            cap <<= 1;
        // create segments and segments[0]
        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;
    }

 2.2 put方法

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

2.3 使用UNsafe解决线程安全问题实例(TODO)

猜你喜欢

转载自blog.csdn.net/qq_21575929/article/details/125037039