使对易失性字段的操作原子化
总览
易失字段的预期行为是,它们在多线程应用程序中的行为应与在单线程应用程序中的行为相同。 禁止它们表现相同的方式,但不能保证它们表现相同的方式。
Java 5.0+中的解决方案是使用AtomicXxxx类,但是这些类在内存(它们添加标头和填充),性能(它们添加引用和对其相对位置的控制很少)方面效率相对较低,并且在语法上不是易于使用。
恕我直言,一个简单的解决方案,如果可变字段能够像预期的那样起作用,那么JVM必须在AtomicFields中支持的方式是当前JMM(Java内存模型)中所禁止的,但不能保证。
为什么要使字段
volatile字段的好处是,它们在线程中可见,并且某些避免重新读取它们的优化已被禁用,因此即使您没有更改它们,也总是要再次检查当前值。
例如不挥发
Thread 2: int a = 5;Thread 1: a = 6;
(后来)
Thread 2: System.out.println(a); // prints 5 or 6
具有挥发性
Thread 2: volatile int a = 5;Thread 1: a = 6;
(后来)
Thread 2: System.out.println(a); // prints 6 given enough time.
为什么不一直使用
易失的读写访问速度要慢得多。 当您写入易失性字段时,它会使整个CPU管道停顿,以确保已将数据写入缓存。 否则,即使在同一线程中,也有可能在下一次读取该值时看到一个旧值(请参阅AtomicLong.lazySet(),这样可以避免流水线停顿)
惩罚可能会慢10倍左右,您不想在每次访问时都这样做。
一个重要的限制是,即使您可能认为对字段的操作也不是原子的。 甚至比通常情况更糟,没有区别。 也就是说,它似乎可以工作很长时间甚至数年,并且由于偶然的更改(例如所使用的Java版本),甚至对象加载到内存中而突然/随机中断。 例如,在运行程序之前加载了哪些程序。
例如更新值
Thread 2: volatile int a = 5;Thread 1: a += 1;
Thread 2: a += 2;
(后来)
Thread 2: System.out.println(a); // prints 6, 7 or 8 even given enough time.
这是一个问题,因为对a的读取和对a的写入是分别完成的,并且您可以获得竞争条件。 99%以上的时间它会表现出预期,但有时却不会。
你能为这个做什么?
您需要使用AtomicXxxx类。 这些将易失性字段包装为具有预期行为的操作。
Thread 2: AtomicInteger a = new AtomicInteger(5);Thread 1: a.incrementAndGet();
Thread 2: a.addAndGet(2);
(后来)
Thread 2: System.out.println(a); // prints 8 given enough time.
我有什么建议?
JVM具有一种按预期方式运行的方法,唯一令人惊讶的事情是您需要使用特殊的类来执行JMM不能保证的工作。 我建议更改JMM以支持并发AtomicClasses当前提供的行为。
在每种情况下,单线程行为都是不变的。 没有看到竞争条件的多线程程序将表现相同。 区别在于,多线程程序不必查看竞争条件,而可以更改基本行为。
当前方法 | 建议语法 | 笔记 |
---|---|---|
x.getAndIncrement() | x ++或x + = 1 | |
x.incrementAndGet() | ++ x | |
x.getAndDecrment() | x–或x-= 1 | |
x.decrementAndGet() | -X | |
x.addAndGet(y) | (x + = y) | |
x.getAndAdd(y) | ((x + = y)-y) | |
x.compareAndSet(e,y) | (x == e?x = y,true:false) |
需要添加逗号语法 在其他语言中使用。 |
所有基本类型(例如布尔,字节,short,int,long,float和double)都可以支持这些操作。
可以支持其他赋值运算符,例如:
当前方法 | 建议语法 | 笔记 |
---|---|---|
原子乘法 | x * = 2; | |
原子减法 | x-= y; | |
原子分裂 | x / = y; | |
原子模量 | x%= y; | |
原子位移 | x << = y; | |
原子位移 | x >> = z; | |
原子位移 | x >>> = w; | |
原子和 | x&=〜y; | 清除位 |
原子或 | x | = z; | 设置位 |
原子异或 | x ^ = w; | 翻转位 |
有什么风险?
这可能会破坏依赖于这些操作的代码,这些代码有时会由于竞争条件而失败。
可能无法以线程安全的方式支持更复杂的表达式。 这可能会导致令人惊讶的错误,因为代码看起来像是正常的,但事实并非如此。 永远不会比当前状态更糟。
JEP 193 –增强挥发性
有一个JEP 193将该功能添加到Java。 一个例子是:
class Usage {volatile int count;int incrementCount() {return count.volatile.incrementAndGet();}
}
恕我直言,这种方法有一些限制。
- 语法是相当重要的变化。 更改JMM可能不需要更改Java语法,也可能不需要更改编译器。
- 这是一种不太通用的解决方案。 支持体积+ =数量等操作可能很有用; 这些是双重类型。
- 开发人员要了解为什么他/她应该使用此代码而不是x ++ ,这会给开发人员带来更多负担;
我不相信使用更麻烦的语法可以更清楚地了解正在发生的事情。 考虑以下示例:
volatile int a, b;a += b;
要么
a.volatile.addAndGet(b.volatile);
要么
AtomicInteger a, b;a.addAndGet(b.get());
作为行,这些操作中的哪个是原子的。 他们都不回答,但是使用Intel TSX的系统可以使这些原子化,如果您要更改这些代码行中任何一个的行为,我都可以使a + = b; 而不是发明一种新的语法,该语法在大多数情况下会做同样的事情,但是可以保证一种语法,而不能保证另一种。
结论
如果JMM保证等效的单线程操作的行为符合多线程代码的预期,则可以消除使用AtomicInteger和AtomicLong的语法和性能开销。
可以使用字节码检测将该功能添加到Java的早期版本中。
翻译自: https://www.javacodegeeks.com/2014/07/making-operations-on-volatile-fields-atomic.html
使对易失性字段的操作原子化相关推荐
- 最大字段和_使对易失性字段的操作原子化
最大字段和 总览 易失性字段的预期行为是,它们在多线程应用程序中的行为应与在单线程应用程序中的行为相同. 禁止它们表现相同的方式,但是不能保证它们表现相同的方式. Java 5.0+中的解决方案是使用 ...
- 易语言 字段重复_使对易失性字段的操作原子化
易语言 字段重复 总览 易失性字段的预期行为是,它们在多线程应用程序中的行为应与在单线程应用程序中的行为相同. 禁止它们表现相同的方式,但是不能保证它们表现相同的方式. Java 5.0+中的解决方案 ...
- 如何手动提取易失性数据
在本文中,我们将运行几个CLI命令,这些命令可帮助取证调查人员尽可能多地从系统收集易失性数据.注意,我们在本文中使用的命令不是完整的命令列表. 在桌面上创建一个名为"case"的文 ...
- 基础才是重中之重~何为原子化操作
占占定义: 原子化操作,操作原子化,这在软件开发中经常被听到,那到底什么是操作原子化呢,其实从字面上不难理解,原子化就是一体化,整体化,原子化操作就是将多个操作组合在一起,要么这个组合一起发生,要么一 ...
- Java可变引用,Java – 对可变对象的易失性引用 – 对对象的字段的更新对所有线程都是可见的...
这两个问题.我们从第二个开始吧. 将新构造的对象分配给易变量变量工作得很好.读取volatile变量的每个线程都将看到一个完全构造的对象.不需要进一步的同步.这种模式通常与不可变类型结合使用. cla ...
- 面向非易失性内存的持久索引数据结构研究综述
点击上方蓝字关注我们 面向非易失性内存的持久索引数据结构研究综述 王永锋, 陈志广 中山大学计算机学院,广东 广州 510006 摘要:随着非易失性内存从理论走向实用,现代存储系统的设计与实现将迎来颠 ...
- Linux文件系统与持久性内存介绍:块设备、闪存(NAND/NOR)、NVDIMM(非易失性内存)、PMEM(PMDK)- ndctl
<持久内存开发套件(Persistent Memory Development Kit-PMDK) - pmem.io: PMDK> <PMDK介绍> <PMDK(NVM ...
- 非易失性内存技术及数据库
非易失性内存技术及数据库 内容 "2013年开始这个项目的研究,当时不确定非易失性内存技术是否可商用.2019年Intel商用了NVM产品,NVM对下一代数据库系统的影响吸引了广大研究者&q ...
- 非易失性数据库系统存储与恢复方法
非易失性数据库系统存储与恢复方法 摘要 非易失性内存的出现从根本上改变了数据库管理系统的内存和持久存储的架构.这些新型NVM设备具有堪比DRAM的速度,但是写到NVM设备后这些数据就具备了持久性.因为 ...
最新文章
- MyEclipse 9.0 正式版公布新闻 下载
- BZOJ 1257 [CQOI2007]余数之和sum ——Dirichlet积
- mysql root远程访问权限_mysql8.0 Server在Windows平台中的安装、初始化和远程访问设置...
- ThreadLocal的学习
- 剑指offer之26-30题解
- Linux Shell脚本_禁用selinux
- TokenInsight:反映区块链行业整体表现的TI指数较昨日同期下跌5.04%
- SQL 难点解决:直观分组
- llinux 查看自己的公网ip
- 教你如何在b站实现炫酷弹幕墙(文末送十六进制颜色代码一览表)
- 议题征集:NGINX Sprint China 2022 线上大会
- java 假币问题_减治法解决假币问题
- 中国有互联网根服务器吗?
- Maya---骨骼的创建
- Cadence 的 Orcad Capture CIS 使用鼠标右键的Show Footprint无法查看元件封装图的问题的解决方法
- 我现在的笔记有哪几个地方?
- 微信小程序上传文件详解
- conexant hd audio音频驱动
- Hadoop-JAVA编写HDFS客户端进行HDFS操作
- 毕业一年感想~微思顾轻展望
热门文章
- 亲身体验Intellij Idea从卡顿到顺畅
- JAVA List集合转Page(分页对象) java 分页 PageModel 测试类TestPagerModel
- python中seaborn画swarm图_Python可视化 | Seaborn5分钟入门(四)——stripplot和swarmplot
- c++ 凸包 分治算法_三维凸包
- mysql如何分析sql执行效率和进行效率优化
- 过程(栈帧结构是干货)
- POJ3904(dfs)
- web api开启错误提示_当HTTP状态代码不足时:处理Web API错误报告
- junit 测试执行顺序_JUnit 5中的测试执行顺序
- 主要矛盾和次要矛盾_次要GC,主要GC与完整GC