美文网首页未分类
volatile无法应对读写改的场景

volatile无法应对读写改的场景

作者: alonwang | 来源:发表于2018-11-14 11:54 被阅读0次
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的自增为例

volatile的读改写
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();
            }
        }
    }
}

https://github.com/deepak-malik/Data-Structures-In-Java/blob/master/src/com/deepak/data/structures/Hashing/ConcurrentHashMap.md

相关文章

网友评论

    本文标题:volatile无法应对读写改的场景

    本文链接:https://www.haomeiwen.com/subject/tkvdfqtx.html