Java 中 long 是不是原子操作?

沙海 2021年6月30日12:38:18Java评论37字数 3930阅读13分6秒阅读模式
摘要

Java 中 long 是不是原子操作? 小哈学Java

Java 中 long 是不是原子操作?

小哈学Java 文章源自JAVA秀-https://www.javaxiu.com/36188.html

Java 中 long 是不是原子操作?文章源自JAVA秀-https://www.javaxiu.com/36188.html

作者:LouisWong文章源自JAVA秀-https://www.javaxiu.com/36188.html

来源:https://my.oschina.net/u/1753415/blog/724242文章源自JAVA秀-https://www.javaxiu.com/36188.html

文章源自JAVA秀-https://www.javaxiu.com/36188.html

Java中long和double的原子性

java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的吗?文章源自JAVA秀-https://www.javaxiu.com/36188.html

JVM中对long的操作是不是原子操作?

首先,通过一段程序对long的原子性进行判断。测试程序如下:文章源自JAVA秀-https://www.javaxiu.com/36188.html

public class LongAtomTest implements Runnable {    private static long field = 0;    private volatile long value;    public long getValue() {        return value;    }    public void setValue(long value) {        this.value = value;    }    public LongAtomTest(long value) {        this.setValue(value);    }    @Override    public void run() {        int i = 0;        while (i < 100000) {            LongAtomTest.field = this.getValue();            i++;            long temp = LongAtomTest.field;            if (temp != 1L && temp != -1L) {                System.out.println("出现错误结果" + temp);                System.exit(0);            }        }        System.out.println("运行正确");    }    public static void main(String[] args) throws InterruptedException {        // 获取并打印当前JVM是32位还是64位的        String arch = System.getProperty("sun.arch.data.model");        System.out.println(arch+"-bit");        LongAtomTest t1 = new LongAtomTest(1);        LongAtomTest t2 = new LongAtomTest(-1);        Thread T1 = new Thread(t1);        Thread T2 = new Thread(t2);        T1.start();        T2.start();        T1.join();        T2.join();    }}

可以看到,程序中有两条线程t1,t2;t1,t2各自不停的给long类型的静态变量field赋值为1,-1;t1,t2每次赋值后,会读取field的值,若field值既不是1又不是-1,就将field的值打印出来。文章源自JAVA秀-https://www.javaxiu.com/36188.html

如果对long的写入和读取操作是原子性的,那么,field的值只可能是1或者-1文章源自JAVA秀-https://www.javaxiu.com/36188.html

运行结果如下:文章源自JAVA秀-https://www.javaxiu.com/36188.html

32-bit出现错误结果-4294967295运行正确

可以看出,当线程t1,t2同时对long进行写的时候,long出现了既不是t1写入的值,又不是t2写入的值。文章源自JAVA秀-https://www.javaxiu.com/36188.html

可以推测,jvm中对long的操作并非原子操作。文章源自JAVA秀-https://www.javaxiu.com/36188.html

为什么对long的操作不是原子的?

JVM内存模型中定义了8中原子操作:文章源自JAVA秀-https://www.javaxiu.com/36188.html

  1. lock:将一个变量标识为被一个线程独占状态文章源自JAVA秀-https://www.javaxiu.com/36188.html

  2. unclock:将一个变量从独占状态释放出来,释放后的变量才可以被其他线程锁定文章源自JAVA秀-https://www.javaxiu.com/36188.html

  3. read:将一个变量的值从主内存传输到工作内存中,以便随后的load操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  4. load:把read操作从主内存中得到的变量值放入工作内存的变量的副本中文章源自JAVA秀-https://www.javaxiu.com/36188.html

  5. use:把工作内存中的一个变量的值传给执行引擎,每当虚拟机遇到一个使用到变量的指令时都会使用该指令文章源自JAVA秀-https://www.javaxiu.com/36188.html

  6. assign:把一个从执行引擎接收到的值赋给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时,都要使用该操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  7. store:把工作内存中的一个变量的值传递给主内存,以便随后的write操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  8. write:把store操作从工作内存中得到的变量的值写到主内存中的变量文章源自JAVA秀-https://www.javaxiu.com/36188.html

其中,与赋值,取值相关的包括 read,load,use,assign,store,write文章源自JAVA秀-https://www.javaxiu.com/36188.html

按照这个规定,long的读写都是原子操作,与我们的实践结果相反,为什会导致这种问题呢?文章源自JAVA秀-https://www.javaxiu.com/36188.html

对于32位操作系统来说,单次次操作能处理的最长长度为32bit,而long类型8字节64bit,所以对long的读写都要两条指令才能完成(即每次读写64bit中的32bit)。文章源自JAVA秀-https://www.javaxiu.com/36188.html

如果JVM要保证long和double读写的原子性,势必要做额外的处理。那么,JVM有对这一情况进行额外处理吗?文章源自JAVA秀-https://www.javaxiu.com/36188.html

针对这一问题可以参考Java语言规范文档:jls-17 Non-Atomic Treatment of double and long文章源自JAVA秀-https://www.javaxiu.com/36188.html

For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.文章源自JAVA秀-https://www.javaxiu.com/36188.html

Writes and reads of volatile long and double values are always atomic.文章源自JAVA秀-https://www.javaxiu.com/36188.html

Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.文章源自JAVA秀-https://www.javaxiu.com/36188.html

Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32-bit values. For efficiency's sake, this behavior is implementation-specific; an implementation of the Java Virtual Machine is free to perform writes to long and double values atomically or in two parts.文章源自JAVA秀-https://www.javaxiu.com/36188.html

Implementations of the Java Virtual Machine are encouraged to avoid splitting 64-bit values where possible. Programmers are encouraged to declare shared 64-bit values as volatile or synchronize their programs correctly to avoid possible complications.文章源自JAVA秀-https://www.javaxiu.com/36188.html

从规定中我们可以知道:文章源自JAVA秀-https://www.javaxiu.com/36188.html

  1. 对于64位的long和double,如果没有被volatile修饰,那么对其操作可以不是原子的。在操作的时候,可以分成两步,每次对32位操作。文章源自JAVA秀-https://www.javaxiu.com/36188.html

  2. 如果使用volatile修饰long和double,那么其读写都是原子操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  3. 对于64位的引用地址的读写,都是原子操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  4. 在实现JVM时,可以自由选择是否把读写long和double作为原子操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

  5. 推荐JVM实现为原子操作文章源自JAVA秀-https://www.javaxiu.com/36188.html

从程序得到的结果来看,32位的HotSpot没有把long和double的读写实现为原子操作。在读写的时候,分成两次操作,每次读写32位。因为采用了这种策略,所以64位的long和double的读与写都不是原子操作。文章源自JAVA秀-https://www.javaxiu.com/36188.html

在硬件,操作系统,JVM都是64位的情况下呢?

对于64bit的环境来说,单次操作可以操作64bit的数据,即可以以一次性读写long或double的整个64bit。因此我们可以猜测,在64位的环境下,long和double的读写有可能是原子操作。在换了64位的JVM之后,多次运行,结果都是正确的文章源自JAVA秀-https://www.javaxiu.com/36188.html

64-bit运行正确运行正确

结果表明,在64bit的虚拟机下,long的处理是原子性的。文章源自JAVA秀-https://www.javaxiu.com/36188.html

1. 为什么索引可以让查询变快,你有思考过吗?2. 牛逼!单点登录系统用 8 张漫画就解释了。。。3. 微服务 API 网关建设,实践经验分享!4. 抖音服务器带宽有多大,才能供上亿人同时刷?最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。文章源自JAVA秀-https://www.javaxiu.com/36188.html

谢谢支持哟 (*^__^*)文章源自JAVA秀-https://www.javaxiu.com/36188.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定