Java中primitive type的线程安全性

Java中primite type,如char,integer,bool之类的,它们的读写操做都是atomic的,可是有几个例外:java

  1. long和double类型不是atomic的,由于long和double都是8字节的,而在32位的CPU上,其机器字长为32位,操做8个字节须要多个指令操做。
  2. ++i或者i++,由于要先读后写,也是多步操做。

这些状况下,须要使用AutomicInteger,AutomicLong。安全

 

同时,java中的reference的读写也是automic的,虽然reference到底占几个字节没有明肯定义,但至少如下能够保证:app

  1. 在32位的CPU下,使用的是4字节的reference
  2. 在64位的CPU下,可使用4字节或者8字节的reference

因此不管如何,对reference的操做确定是单步操做,是automic的。jvm

事实上,一个蛮有用的例子是cache switch - 你有两个cache pool,分别用两个reference指向:cache_in_build和cache_in_use,等cache_in_build完成了,你须要把cache_in_use指向它,没有问题,这是线程安全的。优化

可是问题是,jvm能够会reorder你的statement:ui

  1. cache_in_build.build()
  2. cache_in_use = cache_in_build

指望是cache在build完了以后,切换过去。atom

可是这两行代码并无先后的dependency关系,因此JVM能够为了优化,进行乱序执行,变成:线程

  1. cache_in_use = cache_in_build
  2. cache_in_build.build()

因而,若是另外一个线程在使用cache_in_use,在代码#1执行完以后,就访问到了正在build的那个cache,这是个问题。it

解决方案是cache_in_use必须定义为volatile,保证happen-before的关系,拒绝乱序执行,从而保证其余线程看到的数据是有效的。im

相关文章
相关标签/搜索