Java原子操作、原子性、可见性、内存模型

写这篇博客起源于一道面试题 i++ 是不是原子操作?

那到底什么是原子操作?
所谓原子操作,就是“不可中断的一个或一系列操作”。在确认一个操作是原子的情况下,在多线程环境里,我们可以避免仅仅为保护这个操作在外围加上性能昂贵的锁,甚至借助于原子操作,我们可以实现互斥锁。

Java中有哪些原子操作呢?查询资料后我总结出了以下几个场景:

原始类型:原始类型(long和double的赋值操作在32位操作系统上是非原子操作)的简单读取、写入操作(i++是非原子操作)。
volatile:使用volatile修饰的变量的简单读取、写入操作。
原子类:原子类(例如AtomicInteger、AtomicBoolean)的读取、写入操作,注意incrementAndGet自增操作具有原子性。
并发锁:使用synchronize或者Lock进行限定的并发锁,其中的代码都具有原子性。
注意:volatile并不保证原子性,所以即使变量有volatile修饰,对变量的“复杂”操作并不是原子操作,即保证简单读取、写入操作是原子操作。

下面对相关概念进行一些简单阐述:

1.原子性:

原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1;

2.非原子性:

也就是整个过程中会出现线程调度器中断操作的现象

类似"a++"这样的操作不具有原子性,因为它可能要经过以下两个步骤:

(1)取出 a 的值

(2)计算 a+1

如果有两个线程t1,t2在进行这样的操作。t1在第一步做完之后还没来得及加1操作就被线程调度器中断了,于是t2开始执行,t2执行完毕后t1开始执行第二步(此时t1中a的值可能还是旧值,不是一定的,只有线程t2中a的值没有及时更新到t1中才会出现)。这个时候就出现了错误,t2的操作相当于被忽略了

类似于a += 1这样的操作都不具有原子性。还有一种特殊情况,就是long跟double类型某些情况也不具有原子性,具体可参考:java中long和double类型操作的非原子性探究

 

3.共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这个几个线程的共享变量

4.可见性:一个线程对共享变量值的修改,能够及时的被其它线程看到。

    在多线程的情况下,共享变量不一定是可见的。要想实现变量的一定可见,可以使用synchronized、volatile两种方式(其实还有final,但是它初始化后,值不可  更改,所以一般不用它实现可见性)。具体做法可参考:synchronized实现可见性volatile特性(其中volatile 是比synchronized关键字更加轻量级的同步机制,因为它不需要加锁,也就不会阻塞,所以性能会好点。)。

 

5.Java内存模型(Java Memory Model) 描述了Java程序各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。

   在Java内存模型(以下简称为JMM)中:

  1) 所有的变量都存储在主内存中

  2)每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)

   用下面的图可以直观的看到JMM中,线程、工作内存、主内存之间的关系:

  

    在上面的图中,可以看到线程只与工作内存交互,不能直接访问主内存。当主内存中有一个共享变量X,则工作内存则是将X拷贝,然后线程是操作工作内存中X的副本

    在JMM中,有两条规定:

  1)线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写

  2)不同线程之间无法访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成

    共享变量要实现可见性,必须经过如下两个步骤:

  1)把工作内存1中更新过的共享变量刷新到主内存中

  2)把主内存中最新的共享变量的值更新到工作内存2中

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值