众所周知,并发哈希映射允许多个线程使用段锁同时读/写。 我的问题是: 当线程t1在存储桶上写入并且线程t2在同一存储桶上读取时,Java如何在内部管理映射,反之亦然? Java是否在任何线程开始在地图上写入并在写入操作之后合并它们或者Java采用的实际方式之前是否复制了地图?
等待正确答案。
答案 0 :(得分:1)
不,Java不会复制地图或段,也不会在写入操作后将副本“合并”到地图中。
put
和get
方法锁定了段,因此两个线程无法同时访问同一段。
请查看put
和get
的实施情况:
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)
返回给定哈希的段,然后在此段上调用put
和get
方法。
该段的声明在这里,它是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()
来阻止/允许其他线程在执行工作时访问该段。