您的位置:首页 > 其它

ConcurrentHashMap使用示例

2015-11-14 10:01 197 查看
       ConcurrentHashMap是并发效率更高的Map,用来替换其他线程安全的Map容器,比如Hashtable和Collections.synchronizedMap。实际上,并发执行时,线程安全的容器只能保证自身的数据不被破坏,但无法保证业务的行为是否正确。错误的理解这里的线程安全,不恰当的使用ConcurrentHashMap,往往会导致出现问题。

举个例子:
public static void demo1() {
final Map<String, Integer> count = new ConcurrentHashMap<>();
final CountDownLatch endLatch = new CountDownLatch(2);
Runnable task = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
Integer value = count.get("a");
if (null == value) {
count.put("a", 1);
} else {
count.put("a", value + 1);
}
}
endLatch.countDown();
}
};
new Thread(task).start();
new Thread(task).start();

try {
endLatch.await();
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}
}
       demo1是两个线程操作ConcurrentHashMap,意图将value变为10。但是,因为多个线程用相同的key调用时,很可能会覆盖相互的结果,造成记录的次数比实际出现的次数少。

    当然可以用锁解决这个问题,但是也可以使用ConcurrentMap定义的方法:
V putIfAbsent(K key, V value)
如果key对应的value不存在,则put进去,返回null。否则不put,返回已存在的value。

boolean remove(Object key, Object value)
如果key对应的值是value,则移除K-V,返回true。否则不移除,返回false。

boolean replace(K key, V oldValue, V newValue)
如果key对应的当前值是oldValue,则替换为newValue,返回true。否则不替换,返回false。
于是对demo1进行改进:
public static void demo1() {
final Map<String, Integer> count = new ConcurrentHashMap<>();
final CountDownLatch endLatch = new CountDownLatch(2);
Runnable task = new Runnable() {
@Override
public void run() {
Integer oldValue, newValue;
for (int i = 0; i < 5; i++) {
while (true) {
oldValue = count.get("a");
if (null == oldValue) {
newValue = 1;
if (count.putIfAbsent("a", newValue) == null) {
break;
}
} else {
newValue = oldValue + 1;
if (count.replace("a", oldValue, newValue)) {
break;
}
}
}
}
endLatch.countDown();
}
};
new Thread(task).start();
new Thread(task).start();

try {
endLatch.await();
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}
}
由于ConcurrentMap中不能保存value为null的值,所以需要处理不存在和已存在两种情况,不过可以使用AtomicInteger来替代。
public static void demo1() {
final Map<String, AtomicInteger> count = new ConcurrentHashMap<>();
final CountDownLatch endLatch = new CountDownLatch(2);
Runnable task = new Runnable() {
@Override
public void run() {
AtomicInteger oldValue;
for (int i = 0; i < 5; i++) {
oldValue = count.get("a");
if (null == oldValue) {
AtomicInteger zeroValue = new AtomicInteger(0);
oldValue = count.putIfAbsent("a", zeroValue);
if (null == oldValue) {
oldValue = zeroValue;
}
}
oldValue.incrementAndGet();
}
endLatch.countDown();
}
};
new Thread(task).start();
new Thread(task).start();

try {
endLatch.await();
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: