并发哈希映射Java的内部机制

时间:2016-05-29 06:47:53

标签: java multithreading concurrency concurrenthashmap

众所周知,并发哈希映射允许多个线程使用段锁同时读/写。 我的问题是: 当线程t1在存储桶上写入并且线程t2在同一存储桶上读取时,Java如何在内部管理映射,反之亦然? Java是否在任何线程开始在地图上写入并在写入操作之后合并它们或者Java采用的实际方式之前是否复制了地图?

等待正确答案。

1 个答案:

答案 0 :(得分:1)

不,Java不会复制地图或段,也不会在写入操作后将副本“合并”到地图中。
putget方法锁定了段,因此两个线程无法同时访问同一段。

请查看putget的实施情况:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/ConcurrentHashMap.java#ConcurrentHashMap.put%28java.lang.Object%2Cjava.lang.Object%29

907     public V put(K key, V value) {
908         if (value == null)
909             throw new NullPointerException();
910         int hash = hash(key.hashCode());
911         return segmentFor(hash).put(key, hash, value, false);
912     }

795     public V  get(Object key) {
796         int hash = hash(key.hashCode());
797         return segmentFor(hash).get(key, hash);
798     }

两种方法都计算密钥的哈希值,然后调用segmentFor(hash)返回给定哈希的段,然后在此段上调用putget方法。

该段的声明在这里,它是ReentrantLock的后代:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/ConcurrentHashMap.java#ConcurrentHashMap.Segment

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

并在细分受众群中实施get ang put

351         V  readValueUnderLock(HashEntry<K,V> e) {
352             lock();
353             try {
354                 return e.value;
355             } finally {
356                 unlock();
357             }
358         }
359 
360         /* Specialized implementations of map methods */
361 
362         V  get(Object key, int hash) {
363             if (count != 0) { // read-volatile
364                 HashEntry<K,V> e = getFirst(hash);
365                 while (e != null) {
366                     if (e.hash == hash && key.equals(e.key)) {
367                         V v = e.value;
368                         if (v != null)
369                             return v;
370                         return readValueUnderLock(e); // recheck
371                     }
372                     e = e.next;
373                 }
374             }
375             return null;
376         }
444         V put(K key, int hash, V value, boolean onlyIfAbsent) {
445             lock();
446             try {
447                 int c = count;
448                 if (c++ > threshold) // ensure capacity
449                     rehash();
450                 HashEntry<K,V>[] tab = table;
451                 int index = hash & (tab.length - 1);
452                 HashEntry<K,V> first = tab[index];
453                 HashEntry<K,V> e = first;
454                 while (e != null && (e.hash != hash || !key.equals(e.key)))
455                     e = e.next;
456 
457                 V oldValue;
458                 if (e != null) {
459                     oldValue = e.value;
460                     if (!onlyIfAbsent)
461                         e.value = value;
462                 }
463                 else {
464                     oldValue = null;
465                     ++modCount;
466                     tab[index] = new HashEntry<K,V>(key, hash, first, value);
467                     count = c; // write-volatile
468                 }
469                 return oldValue;
470             } finally {
471                 unlock();
472             }
473         }

这些方法只需调用lock()unlock()来阻止/允许其他线程在执行工作时访问该段。