看到大型网站系统与Java中间件实践里边有提到直接将HashMap替换成ConcurrentHashMap时会有问题,所以我写了一段代码测试一下,测试一个数组中字符串出现的次数,结果真的有问题额。
package com.yy.ent.platform.ecommerce.common;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class ConHashMapTest {
private static ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<String,Integer>();
private static String[] array = {"yy","yy","welcome","java","234","java","1234","yy","welcome","java","234"};
public static void main(String[] args) {
System.out.println("array size:"+array.length);
for (String str : array) {
new Thread(new MyTask(str)).start();
}
for(Entry<String,Integer> entry : map.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
static class MyTask implements Runnable{
String key;
public MyTask(String key) {
this.key = key;
}
@Override
public void run() {
map.putIfAbsent(key, value)
Integer value = map.get(key);
if(null == value){
map.put(key, 1);
}else{
map.put(key, value + 1);
}
}
}
}
运行结果:
很明显结果不正确。因为我们对map的值修改要依赖上一次的值,在多线程的环境下就会出问题,如果对于key相同就会发生漏统计,但是我还是比较疑惑测试出来的结果,key为什么会少呢,下面我对map加锁然后程序产生正确结果。
package com.yy.ent.platform.ecommerce.common;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class OptimizedConHashMapTest {
private static ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<String,Integer>();
private static String[] array = {"yy","yy","welcome","java","234","java","1234","yy","welcome","java","234"};
public static void main(String[] args) {
System.out.println("array size:"+array.length);
for (String str : array) {
new Thread(new MyTask(str)).start();
}
for(Entry<String,Integer> entry : map.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
static class MyTask implements Runnable{
String key;
public MyTask(String key) {
this.key = key;
}
@Override
public void run() {
synchronized(map){
Integer value = map.get(key);
if(null == value){
map.put(key, 1);
}else{
map.put(key, value + 1);
}
}
}
}
}
运行结果:
结果正确。如果对于值的修改要依赖上一次的值,还是直接给HashMap加锁实现好了;如果修改的值不依赖上一次的值就用ConcurrentHashMap。