【问题标题】:Concurrent hash map Java's internal mechanismConcurrenthashmap Java内部机制
【发布时间】:2016-05-29 06:47:52
【问题描述】:

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

等待正确答案。

【问题讨论】:

  • 一些基本的谷歌搜索是有序的:javahungry.blogspot.com/2015/02/…
  • 更好的是,这样的问题只要看源码就可以回答了。
  • 我已经完成了它,它只是提到了什么是可能的,什么是不可能的。它没有描述java如何处理它。如果您知道答案,请回答。为什么你标记为不合适。不知道答案的可以跳过。
  • “等待正确答案。” - 我正要回答,但后来我看到了这个。我的回答可能不正确……所以我最好不要告诉你它是什么。 :-)
  • “它没有描述 java 是如何处理它的。” - 那是垃圾。源代码(Java,而不是 cmets)是执行的内容。它准确地说明了会发生什么。如果您无法从 cmets 获得所需的内容,请阅读代码。不要让别人为你做这件事。

标签: java multithreading concurrency concurrenthashmap


【解决方案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() 来阻止/允许其他线程在执行其工作时访问/访问该段。

【讨论】:

    猜你喜欢
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 2012-08-12
    • 2011-02-19
    • 2014-01-10
    • 2020-08-22
    • 2014-03-20
    相关资源
    最近更新 更多