JAVA HashMap与ConcurrentHashMap

HashMap

Fast-Fail (writing operation exception traversal)

In the process of using an iterator if HashMap is modified, it ConcurrentModificationExceptionwill be thrown, namely Fast-fail policy.

When the HashMap iterator () method is called, and it will return a new constructed EntryIterator object and EntryIterator is set to the HashMap expectedModCount ModCount (recording the number of times the variable is modified HashMap).

HashIterator() {
  expectedModCount = modCount;
  if (size > 0) { // advance to first entry
  Entry[] t = table;
  while (index < t.length && (next = t[index++]) == null)
    ;
  }
}

During his visit next Entry by next method Iterator, it will first check with their expectedModCount HashMap of modCount are equal, if not equal, indicating that HashMap is modified, a direct throw ConcurrentModificationException. Remove methods of the Iterator will do a similar check. The exception is thrown as soon as possible aware of the security thread is intended to alert the user.

tableSizeFor方法

tableSizeFor function is to return and the number of the nearest integer power of 2 greater than the input parameters . Such as 10, 16 is returned.

   static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
    static final int MAXIMUM_CAPACITY = 1 << 30;

Analysis again asked what minus one

  int n = cap - 1;

Let cap-1 re-assigned to another purpose n is greater than or equal to find the target original value. 1000 such as binary, decimal value of 8. If it does not operate directly decremented, the answer 10,000, i.e., 16. Obviously not the result. Save the binary 1 is 111, then the operation will give the original value 1000, i.e., 8.

HashMap in the MAXIMUM_CAPACITY is 2 ^ 30 ^. Achieve, I guess the reasons set binding tableSizeFor () as follows:
positive int of up to 2 ^ 31 -1, and no way to get to 2 ^ 31 ^. So capacity can not be up to 2 ^ 31 ^. We need to have the capacity to meet the power of two. It is set to 2 ^ 30 ^

ConcurrentHashMap

Segment inherited from ReentrantLock, so we can easily unlocked for each Segment.

Read (get)

For read operations, acquiring Segment Key is located, the need to ensure visibility (please refer to how to ensure the visibility of multi-threaded condition ). You can use the volatile keyword on the specific implementation, the lock can also be used. However, the use of lock overhead is too large, and each write operation will allow the use of volatile cache invalid in all CPU, there is a certain overhead. ConcurrentHashMap use the following method to ensure visibility, to get the latest Segment.

Segment<K,V> s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)

Getting Segment in HashEntry also used a similar method

HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
  (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE)

Write (put, remove)

Write operation, while not required to obtain a lock Segment of all, because that is equivalent to the entire locked Map. It will first acquire locks on the Key-Value Segment resides, to obtain the same operation after the success of the Segment operating like an ordinary HashMap, and to ensure the safety of the Segment.
Segment same time as the other lock has not been acquired, so in theory can support concurrencyLevel (equal to the number of Segment) a thread-safe concurrent read and write.

Acquiring a lock, not directly used to acquire lock, since the method for obtaining hang (refer to the lock fails reentrant lock ). In fact, it uses a spin lock, if tryLock acquire the lock fails, the lock being used by another thread, this time through the loop again tryLock way to apply the lock. If during the cycle corresponding to the Key list head is modified, the retry reset times. If the retry count exceeds a certain value, then lock the lock request method.

As used herein spin lock spin lock is more efficient, but it consumes more CPU resources, so as to switch the mutex spin value exceeds a threshold number.

to sum up

Compared with HashMap ConcurrentHashMap, following point

  • ConcurrentHashMap thread-safe, non-thread-safe and HashMap
  • HashMap allows Key and Value is null, and is not allowed ConcurrentHashMap
  • HashMap Iterator allowed by simultaneously traversed by modifying HashMap, while allowing the ConcurrentHashMap behavior, and the update for subsequent traversal visible

reference:

The Java7 / 8 HashMap and full resolution ConcurrentHashMap

Advanced Java (six) see Java multithreaded core technology from the evolution of ConcurrentHashMap

Guess you like

Origin www.cnblogs.com/hongdada/p/11937068.html