java中如何应对读改写场景
前言
volatile可以确保数据及时刷新到主存,但是对于读改写场景还是无能为力
举个例子
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确保了读取到的是最新的值,符合语义,那么该如何解决上面的问题呢使用原子类
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();}}}
}
复制代码
主要参考这篇文章
java中如何应对读改写场景相关推荐
- Java中那些内存泄漏的场景!
虽然Java程序员不用像C/C++程序员那样时刻关注内存的使用情况,JVM会帮我们处理好这些,但并不是说有了GC就可以高枕无忧,内存泄露相关的问题一般在测试的时候很难发现,一旦上线流量起来可能马上就是 ...
- java中会用到二进制吗,java中的二进制运算以使用场景
本文知识点 Java 中用二进制使用场景 Java 中声明二进制数据 Java 中拼接二进制数据 二进制的使用场景 做标识用 二进制就是只有 0 和 1 这两个数.这和我们现实很多场景都类似, 如男/ ...
- 谈谈 Java 中自定义注解及使用场景
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:快给我饭吃 www.jianshu.com/p/a7bedc ...
- java 判断文件是否可读_如何检查文件在Java中是否可读,可写或可执行?
通常,无论何时创建文件,都可以限制/允许某些用户读取/写入/执行文件. 在Java文件中(它们的抽象路径)由java.io包的File类表示.此类提供了各种方法来对文件执行各种操作,例如读取,写入,删 ...
- Java中静态变量的适用场景
Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量.因此在某些时候为了节省系统内存开销.共享资源,可以将类中的一些变量声明为静态变量,通过下面 ...
- java 字符串原子变量,如何在java中提供原子读/写2个变量?
在我的课堂上,我的代码如下: int counter1; int counter2; public void method1(){ if (counter1>0) { ...........do ...
- Java中的互斥锁介绍
前言 互斥锁是一种广泛应用于多线程编程中的并发控制机制.在Java中,互斥锁有很多不同的实现方式,在本文中我们将介绍Java中常见的几种互斥锁实现方式,并讲解它们的用法.原理和代码案例. sync ...
- 深入分析 Java 中的中文编码问题(键人岐)
编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多.本文将向你详细介绍 Java 中编码问题出现的根本原因,你将了解到:Java 中 ...
- Java中的内存泄露的几种可能
转载自 Java中的内存泄露的几种可能 Java内存泄漏引起的原因: 内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏. 长生命周 ...
最新文章
- CodeForces 157A Game Outcome
- qtcreator cannot find -lts
- java如何写对象配置文件,Java 读写Properties配置文件详解
- 刚回到北京,倒时差中……
- Windows界面编程-背景图片、透明特效使用
- matlab delete、clf、cla、close、closereq删除对象
- 【科普】OFFICE 365 outlook 如何导入其他邮箱的联系人
- 为什么说容器的崛起预示着云原生时代到来?
- 20171221L09-10老男孩Linux运维实战培训-Nginx服务生产实战应用指南02
- 一次Python性能调优经历
- Python 数据结构与算法——插入排序(insertion sort)
- 求三角形面积(C++)
- android:launchMode=“singleTask“
- 英文词根词典简化笔记
- html-QQ登陆界面
- 振耀退休感言及海辉执行董事长视频访谈
- Android WallpaperManager 同时设置桌面壁纸与锁屏的问题
- Web——HTML常见标签及用法
- Vue将HTML内容用打印机打印出来
- 互联网产品需求分析思路与方法