public class ConcurrentHashMapExample {
public static void main(String[] args) throws InterruptedException {
Map<String, Long> ordersMap = new ConcurrentHashMap<>();
ordersMap.put("Delhi", 0l);
ordersMap.put("London", 0l);
ordersMap.put("New York", 0l);
ordersMap.put("Sydney", 0l);
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(() -> processOrders(ordersMap));
service.submit(() -> processOrders(ordersMap));
service.awaitTermination(3, TimeUnit.SECONDS);
service.shutdown();
System.out.println(ordersMap);
}
private static void processOrders(Map<String, Long> ordersMap) {
for (String city : ordersMap.keySet()) {
for (int i = 0; i < 50; i++) {
Long oldOrder = ordersMap.get(city);
ordersMap.put(city, oldOrder + 1);
}
}
}
}
正确输出应该是
{Delhi=100, New York=100, London=100, Sydney=100}
但是试着多运行几遍,会就发现如下的情况
{Delhi=51, New York=73, London=71, Sydney=100}
在ConcurrentHashMap中value是用volatile修饰的,为什么还会出现这个情况呢?
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}
对于读改写操作,volatile并不能保证正确,需要使用原子类解决
以volatile的自增为例
![](https://img.haomeiwen.com/i2400535/256cb2db2557d891.png)
volatile确保了读取到的是最新的值,符合语义,那么该如何解决上面的问题呢
使用原子类
public class ConcurrentHashMapExample {
public static void main(String[] args) throws InterruptedException {
Map<String, AtomicLong> ordersMap = new ConcurrentHashMap<>();
ordersMap.put("Delhi", new AtomicLong(0L));
ordersMap.put("London", new AtomicLong(0L));
ordersMap.put("New York", new AtomicLong(0L));
ordersMap.put("Sydney", new AtomicLong(0L));
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(() -> processOrders(ordersMap));
service.submit(() -> processOrders(ordersMap));
service.awaitTermination(1, TimeUnit.SECONDS);
service.shutdown();
System.out.println(ordersMap);
}
private static void processOrders(Map<String, AtomicLong> ordersMap) {
for (String city : ordersMap.keySet()) {
for (int i = 0; i < 50; i++) {
ordersMap.get(city).incrementAndGet();
}
}
}
}
网友评论