原子性和可见性的理解

并发编程中常见的两个问题:原子性和可见性,虽然经常讨论,但是只是停留在应用层面,理解仍然还不是特别深刻。做个笔录加深一下自己的理解。

原子性:定义为不可被分割的操作。单个指令可以是原子的,多个指令通过加锁的方式也可以实现原子性。原子性可以是针对单核多线程,也可以针对多核多线程。

1)单核多线程:原子性的指令不可以被中断,一定要执行完该条指令之后才可以切换上下文。加锁实现的原子性因为只是以互斥的方式实现,是可以被中断的。

例如:http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7

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.

当读写非volatile long or double时,因为不是原子性,就可能导致即使单核但是多线程也会发生不一致。


2)多核多线程:因为每个核心都会有自己的寄存器,cache,相互交互数据比较麻烦,除了支持原子性之外,还要体现的就是可见性。在单核多线程下,在CPU级别的可见性是固有存在的(每个线程下如果各自缓存了变量仍会发生不一致)。在多核多线程下,一个线程修改了数据,另一个核心的线程是否能看见修改的数据(因为另一个核心可能从自己的寄存器加载数据,也有可能前一个核心只把数据修改到了寄存器或缓存中,没有刷到内存中),这时就对可见性有了要求。

仍然是上面的例子,对volatile long和double的读写总是原子的,同时也能保证可见性。


总结:

原子性保证了数据的完整性,不能像狮身人面像一样,没有保证原子性(just a joke);可见性保证了线程1修改完数据A后,数据A对其他线程也是可见的。在java开发过程中,一些常用的工具类如AtomicLong等,虽然以原子命名,但是同时具备可见性。但是哪些操作是只具备原子性不具备可见性呢?CPU指令是原子的,但是不一定具备多线程可见性。

在并发编程中,不管是单核或是多核,一定要同时考虑两个以上两个特性,不然就会出现线程安全的问题。

第二个例子也同时说明,在开发Java程序中,JVM本身就支持volatile long和double的原子性,当没有强功能时,也许并不需要使用java.util.concurrent.atomic.AtomicLong。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值