Java. util. concurrent package source code reading 04 ConcurrentMap, java. util package

Source: Internet
Author: User
Tags map data structure rehash

Java. util. concurrent package source code reading 04 ConcurrentMap, java. util package

The Map data structure in the Java Collection framework is non-thread-safe. Manual thread synchronization is required for use in a multi-threaded environment. Therefore, the java. util. concurrent package provides a thread-safe version of the Map-type data structure: ConcurrentMap. This article focuses on the ConcurrentMa interface and its implementation of the Hash version ConcurrentHashMap.

ConcurrentMap is a sub-interface of the Map interface.

public interface ConcurrentMap<K, V> extends Map<K, V>

Compared with the Map interface, ConcurrentMap has four more methods:

1) putIfAbsent method: if the key does not exist, add key-value. The method returns the value associated with the key.

V putIfAbsent(K key, V value);

2) remove Method

boolean remove(Object key, Object value);

The Map interface also has a remove method:

V remove(Object key);

The remove Method in ConcurrentMap needs to compare whether the original value and the value in the parameter are consistent. Only the same method will be deleted.

3) Replace method: There are two reloads

boolean replace(K key, V oldValue, V newValue);V replace(K key, V value);

The differences between the two overload methods are similar to the differences between the two remove methods in 2). If there is one more check, the value is the same.

 

The ConcurrentMap method shows a very important concept in multithreading: compare. Compare is used to ensure value consistency.

 

The first scene is ConcurrentHashMap.

public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>        implements ConcurrentMap<K, V>, Serializable

ConcurrentHashMap is similar to HashMap. Here we focus on how to implement thread security, that is, how to lock.

For HashMap, there is an Entry array. Based on the hash value of the Key, modulo the array length to obtain the array subscript, locate the Entry, and traverse the entire Entry linked list, use equals to determine the Entry where the key is located.

The basic idea of ConcurrentHashMap is to lock the chunks. The number of chunks is determined by the parameter "concurrencyLevel" (similar to "initialCapacity" in HashMap, the actual number of blocks is the first N power greater than concurrencyLevel ). Each part is called a Segment. The index method of the Segment is the same as that of the Entry index in HashMap (the hash value modulo the array length ).

The method for locking a Segment is simple. You can define a Segment as a subclass of ReentrantLock. At the same time, Segment is a specific hash table.

static final class Segment<K,V> extends ReentrantLock implements Serializable

The following describes how to lock ConcurrentHashMap during read/write.

The first is the read operation method. Let's look at the get method:

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

We can see that the method for obtaining the lock of the Segment is not called during the reading, but the Entry is located through the hash value, and then the linked list of the Entry is traversed. Why don't I need to lock it here? Check out the HashEntry code and you will understand it.

    static final class HashEntry<K,V> {        final int hash;        final K key;        volatile V value;        volatile HashEntry<K,V> next;

The value and next attributes carry the volatile modifier, allowing you to traverse and compare them with confidence.

 

The next step is the write operation. The write operation must be locked. Because Segment can be considered as a hash table, ConcurrentHashMap directly calls the corresponding write method of Segment, such as put and replace.

For example, put Method

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

Therefore, you can directly follow the corresponding write operation method of Segment. The following code is used at the beginning of each write operation:

        final V remove(Object key, int hash, Object value) {            if (!tryLock())                scanAndLock(key, hash);
            HashEntry<K,V> node = tryLock() ? null :                scanAndLockForPut(key, hash, value);

That is, first try to get the lock. If the lock is successful, the Operation will continue. If the lock fails, you must use scanAndLock or scanAndLockForPut to get the lock. Therefore, the focus here will be shifted to the two methods.

According to the rules of the multi-threaded environment, if the attempt to obtain the lock fails, it will enter the blocking wait state, then the role of the two methods should be similar.

        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {            HashEntry<K,V> first = entryForHash(this, hash);            HashEntry<K,V> e = first;            HashEntry<K,V> node = null;            int retries = -1; // negative while locating node            while (!tryLock()) {                HashEntry<K,V> f; // to recheck first below                if (retries < 0) {                    if (e == null) {                        if (node == null) // speculatively create node                            node = new HashEntry<K,V>(hash, key, value, null);                        retries = 0;                    }                    else if (key.equals(e.key))                        retries = 0;                    else                        e = e.next;                }                else if (++retries > MAX_SCAN_RETRIES) {                    lock();                    break;                }                else if ((retries & 1) == 0 &&                         (f = entryForHash(this, hash)) != first) {                    e = first = f; // re-traverse if entry changed                    retries = -1;                }            }            return node;        }

The logic of the two methods: When waiting, you have nothing to do to prepare for it. Find the target entry. If you create a new entry, you can create the entry, then, if everything is okay, use the lock () method to block yourself, that is, prepare and wait.

 

Because Segment itself can be regarded as a hash table, it must involve the rehash problem, because it is similar to the rehash in HashMap and is omitted here.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.