大家都知道hashmap不是线程安全的,但是大家的理解可能都不是十分准确。很显然读写同一个key会导致不一致大家都能理解,但是如果读写一个不变的对象会有问题么?看看下面的代码就明白了。
1 import java.util.hashmap;
2 import java.util.map;
3 import java.util.random;
4 import java.util.concurrent.executorservice;
5 import java.util.concurrent.executors;
6 import java.util.concurrent.timeunit;
7 import java.util.concurrent.atomic.atomicinteger;
8
9 public class hashmaptest2 {
10 static void doit() throws exception{
11 final int count = 200;
12 final atomicinteger checknum = new atomicinteger(0);
13 executorservice newfixedthreadpool = executors.newfixedthreadpool(100);
14 //
15 final map<long, string> map = new hashmap<long, string>();
16 map.put(0l, "www.imxylz.cn");
17 //map.put(1l, "www.imxylz.cn");
18 for (int j = 0; j < count; j) {
19 newfixedthreadpool.submit(new runnable() {
20 public void run() {
21 map.put(system.nanotime()new random().nextlong(), "www.imxylz.cn");
22 string obj = map.get(0l);
23 if (obj == null) {
24 checknum.incrementandget();
25 }
26 }
27 });
28 }
29 newfixedthreadpool.awaittermination(1, timeunit.seconds);
30 newfixedthreadpool.shutdown();
31
32 system.out.println(checknum.get());
33 }
34
35 public static void main(string[] args) throws exception{
36 for(int i=0;i<10;i) {
37 doit();
38 thread.sleep(500l);
39 }
40 }
41 }
42
结果一定会输出0么?结果却不一定。比如某一次的结果是:
0
3
0
0
0
0
9
0
9
0
查看了源码,其实出现这个问题是因为hashmap在扩容是导致了重新进行hash计算。
在hashmap中,有下面的源码:
1 public v get(object key) {
2 if (key == null)
3 return getfornullkey();
4 int hash = hash(key.hashcode());
5 for (entry<k,v> e = table[indexfor(hash, table.length)];
6 e != null;
7 e = e.next) {
8 object k;
9 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10 return e.value;
11 }
12 return null;
13 }
在indexof中就会导致计算有偏移。
1 static int indexfor(int h, int length) {
2 return h & (length-1);
3 }
很显然在map的容量(table.length,数组的大小)有变化时就会导致此处计算偏移变化。这样每次读的时候就不一定能获取到目标索引了。为了证明此猜想,我们改造下,变成以下的代码。
final map<string, string> map = new hashmap<string, string>(10000);
执行多次结果总是输出:
0
0
0
0
0
0
0
0
0
0
当然了如果只是读,没有写肯定没有并发的问题了。改换hashtable或者concurrenthashmap肯定也是没有问题了。
这里有一篇完整分析hashmap原理的文章。 __ by xylz 2010.07.20