博主信息
Sky
博文
291
粉丝
0
评论
0
访问量
6381
积分:0
P豆:617

Java 中 long 是不是原子操作?

2021年10月20日 21:38:28阅读数:25博客 / Sky

Java中long和double的原子性

java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的吗?

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

首先,通过一段程序对long的原子性进行判断。测试程序如下:

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的值打印出来。

如果对long的写入和读取操作是原子性的,那么,field的值只可能是1或者-1

运行结果如下:

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

可以看出,当线程t1,t2同时对long进行写的时候,long出现了既不是t1写入的值,又不是t2写入的值。

可以推测,jvm中对long的操作并非原子操作。

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

JVM内存模型中定义了8中原子操作:

1.lock:将一个变量标识为被一个线程独占状态
2.unclock:将一个变量从独占状态释放出来,释放后的变量才可以被其他线程锁定
3.read:将一个变量的值从主内存传输到工作内存中,以便随后的load操作
4.load:把read操作从主内存中得到的变量值放入工作内存的变量的副本中
5.use:把工作内存中的一个变量的值传给执行引擎,每当虚拟机遇到一个使用到变量的指令时都会使用该指令
6.assign:把一个从执行引擎接收到的值赋给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时,都要使用该操作
7.store:把工作内存中的一个变量的值传递给主内存,以便随后的write操作
8.write:把store操作从工作内存中得到的变量的值写到主内存中的变量

其中,与赋值,取值相关的包括 read,load,use,assign,store,write

按照这个规定,long的读写都是原子操作,与我们的实践结果相反,为什会导致这种问题呢?

对于32位操作系统来说,单次次操作能处理的最长长度为32bit,而long类型8字节64bit,所以对long的读写都要两条指令才能完成(即每次读写64bit中的32bit)。

如果JVM要保证long和double读写的原子性,势必要做额外的处理。那么,二手卖号平台JVM有对这一情况进行额外处理吗?

针对这一问题可以参考Java语言规范文档:jls-17 Non-Atomic Treatment of double and long

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.

Writes and reads of volatile long and double values are always atomic.

Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.

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.

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.

从规定中我们可以知道:

1.对于64位的long和double,如果没有被volatile修饰,那么对其操作可以不是原子的。在操作的时候,可以分成两步,每次对32位操作。
2.如果使用volatile修饰long和double,那么其读写都是原子操作
3.对于64位的引用地址的读写,都是原子操作
4.在实现JVM时,可以自由选择是否把读写long和double作为原子操作
5.推荐JVM实现为原子操作

从程序得到的结果来看,32位的HotSpot没有把long和double的读写实现为原子操作。在读写的时候,分成两次操作,每次读写32位。因为采用了这种策略,所以64位的long和double的读与写都不是原子操作。

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

对于64bit的环境来说,单次操作可以操作64bit的数据,即可以以一次性读写long或double的整个64bit。因此我们可以猜测,在64位的环境下,long和double的读写有可能是原子操作。在换了64位的JVM之后,多次运行,结果都是正确的

64-bit
运行正确
运行正确

结果表明,在64bit的虚拟机下,long的处理是原子性的。


版权申明:本博文版权归博主所有,转载请注明地址!如有侵权、违法,请联系admin@php.cn举报处理!

全部评论

文明上网理性发言,请遵守新闻评论服务协议

条评论
  • c和java的区别:1、Java有面向对象OO成分在里面,而C完全面向过程的;2、Java跨平台,既同的系统都可以通过JVM来解释Java程序,而C、C++、C#则与平台相关的,有些指令只在某些系统才能执行
    extends在java继承的意思,在Java,通过关键字extends继承一个已有的类,被继承的类称为父类【超类,基类】,新的类称为类【派生类】,并且在Java允许多继承。

    2021-01-08

    321

    pdf全称Portable Document Format,文意思“可携带文档格式”,一种电文件格式。
    在本教程,我们将探讨如何在浏览器使用 JavaScript 库来图片,为服务器上的存储做准备,并在 Web 程序使用。我们将使用 Vue.js 而生 JavaScript来完成此
    数据库事务的四个特征:1、性,事务数据库的逻辑工单位,事务要么全做,要么做;2、一致性,一个事务执行之前和执行之后都必须处于一致性状态;3、隔离性;4、持久性, 一个事务一旦提交,他对数据库的数据的改变应该永久性的
    cpu和芯片同一个概念,两者区别:1、功能同,电脑所有都由CPU负责读取指令,而芯片提供对CPU的类型和主频等支持;2、构成同,cpu各电元件构成的计算机央处理器的统称;3、定义
    outputstreamjava的字节输出流,它能用来将文件或者字符串输出到新的文件,其使用方法:首先使用File类打开一个文件;然后通过流的类来指定位置;接着进行输入或输出;最后关闭“输入
    Java定义接口的关键字“interface”。“interface”面向对象编程语言接口的关键字,功能把所需成员组合起来,用来装封一定功能的集合。

    2021-02-03

    818

    “.doc”电脑文件常见扩展名的一种,也Word2003以前版本的文本文档,自Word2007之后为docx;doc格式纯文本文件使用的,多见于同的系统,软硬件的使用说明。
    智能对象包含栅格或矢量图像的图像数据的图层,它将保留图像的源内容及其所有始特性,从而能够对图层执行非破坏性编辑。可以对图层进行,而会丢失始图像数据或降低品质,会影响始数据。
    java,多态同一个行为具有多个同表现形式或形态的能力;​多态就同一个接口,使用同的实例而执行
    电脑的安全模式Windows系统的一种特殊模式,工加载第三方设备驱动程序的情况下启动电脑,使电脑运行在系统最小模式,这样用户就可以方便地检测与修复计算机系统的错误。
    Java语言的三大特征:封装、继承、多态。
    php支持unicode指PHP字符串保存字符的编码信息,所以函数,并知道二进制数据该如何对应文本,只能假设一个字符对应单个字节;这样在处理英文等ascii码时就够用,但对于文等多字节字符
    下面由thinkphp框架教程栏目给大家介绍ThinkPHP框架SQL链式写法理,希望对需要的朋友有所帮助!大家如果有面试几次难发现,虽然国产的TP一直被人诟病。
    键盘上的上下左右键能用的解决办法:1、将键盘拿到另一台电脑做测试,若有问题则修理或更换;2、用系统自带的系统还;3、使用系统盘修复;4、在BIOS设置光驱为第一启动设备插入系统安装盘,按R键选择