1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
V get(Object key, int
hash) { if
(count != 0 ) { // read-volatile HashEntry e = getFirst(hash); while
(e != null ) { if
(e.hash == hash && key.equals(e.key)) { V v = e.value; if
(v != null ) return
v; return
readValueUnderLock(e); // recheck } e = e.next; } } return
null ; } |
1
2
3
4
5
6
7
8 |
V readValueUnderLock(HashEntry e) { lock(); try
{ return
e.value; } finally
{ unlock(); } } |
put操作一上来就锁定了整个segment,这当然是为了并发的安全,修改数据是不能并发进行的,必须得有个判断是否超限的语句以确保容量不足时能够rehash,而比较难懂的是这句int index = hash & (tab.length - 1),原来segment里面才是真正的hashtable,即每个segment是一个传统意义上的hashtable,如上图,从两者的结构就可以看出区别,这里就是找出需要的entry在table的哪一个位置,之后得到的entry就是这个链的第一个节点,如果e!=null,说明找到了,这是就要替换节点的值(onlyIfAbsent ==false),否则,我们需要new一个entry,它的后继是first,而让tab[index]指向它,什么意思呢?实际上就是将这个新entry插入到链头,剩下的就非常容易理解了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 |
V put(K key, int
hash, V value, boolean
onlyIfAbsent) { lock(); try
{ int
c = count; if
(c++ > threshold) // ensure capacity rehash(); HashEntry[] tab = table; int
index = hash & (tab.length - 1 ); HashEntry first = (HashEntry) tab[index]; HashEntry e = first; while
(e != null
&& (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue; if
(e != null ) { oldValue = e.value; if
(!onlyIfAbsent) e.value = value; } else
{ oldValue = null ; ++modCount; tab[index] = new
HashEntry(key, hash, first, value); count = c; // write-volatile } return
oldValue; } finally
{ unlock(); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
V remove(Object key, int
hash, Object value) { lock(); try
{ int
c = count - 1 ; HashEntry[] tab = table; int
index = hash & (tab.length - 1 ); HashEntry first = (HashEntry)tab[index]; HashEntry e = first; while
(e != null
&& (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null ; if
(e != null ) { V v = e.value; if
(value == null
|| value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; HashEntry newFirst = e.next; * for
(HashEntry p = first; p != e; p = p.next) * newFirst = new
HashEntry(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return
oldValue; } finally
{ unlock(); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13 |
static final class HashEntry { final
K key; final
int hash; volatile
V value; final
HashEntry next; HashEntry(K key, int
hash, HashEntry next, V value) { this .key = key; this .hash = hash; this .next = next; this .value = value; } } |
以上,分析了几个最简单的操作,限于篇幅,这里不再对rehash或iterator等实现进行讨论,有兴趣可以参考src。
接下来实际上还有一个疑问,ConcurrentHashMap跟HashMap相比较性能到底如何。这在Brian Goetz的文章中已经有过评测http://www.ibm.com/developerworks/cn/java/j-jtp07233/。
ConcurrentHashMap 并发HashMap原理分析,布布扣,bubuko.com
ConcurrentHashMap 并发HashMap原理分析
原文:http://www.cnblogs.com/sunfb/p/3678383.html