前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >内存可见性和原子性:Synchronized和Volatile的比较

内存可见性和原子性:Synchronized和Volatile的比较

作者头像
traffic
发布2020-04-09 15:33:27
1.4K0
发布2020-04-09 15:33:27
举报
文章被收录于专栏:大龄码农大龄码农

Java多线程之内存可见性和原子性:Synchronized和Volatile的比较

尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/52525724

在说明Java多线程内存可见性之前,先来简单了解一下Java内存模型。

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

(1)线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接在主内存中读写 (2)不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。 线程1对共享变量的修改,要想被线程2及时看到,必须经过如下2个过程: (1)把工作内存1中更新过的共享变量刷新到主内存中 (2)将主内存中最新的共享变量的值更新到工作内存2中

可见性与原子性

可见性:一个线程对共享变量的修改,更够及时的被其他线程看到 原子性:即不可再分了,不能分为多步操作。比如赋值或者return。比如"a = 1;"和 "return a;"这样的操作都具有原子性。类似"a += b"这样的操作不具有原子性,在某些JVM中"a += b"可能要经过这样三个步骤: ① 取出a和b ② 计算a+b ③ 将计算结果写入内存

(1)Synchronized:保证可见性和原子性 Synchronized能够实现原子性和可见性;在Java内存模型中,synchronized规定,线程在加锁时,先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁

(2)Volatile:保证可见性,但不保证操作的原子性 Volatile实现内存可见性是通过store和load指令完成的;也就是对volatile变量执行写操作时,会在写操作后加入一条store指令,即强迫线程将最新的值刷新到主内存中;而在读操作时,会加入一条load指令,即强迫从主内存中读入变量的值。但volatile不保证volatile变量的原子性,例如:

[java] view plain copy

  1. Private int Num=0;
  2. Num++;//Num不是原子操作

Num不是原子操作,因为其可以分为:读取Num的值,将Num的值+1,写入最新的Num的值。 对于Num++;操作,线程1和线程2都执行一次,最后输出Num的值可能是:1或者2 【解释】输出结果1的解释:当线程1执行Num++;语句时,先是读入Num的值为0,倘若此时让出CPU执行权,线程获得执行,线程2会重新从主内存中,读入Num的值还是0,然后线程2执行+1操作,最后把Num=1刷新到主内存中; 线程2执行完后,线程1由开始执行,但之前已经读取的Num的值0,所以它还是在0的基础上执行+1操作,也就是还是等于1,并刷新到主内存中。所以最终的结果是1

一般在多线程中使用volatile变量,为了安全,对变量的写入操作不能依赖当前变量的值:如Num++或者Num=Num*5这些操作。

(3)Synchronized和Volatile的比较 1)Synchronized保证内存可见性和操作的原子性 2)Volatile只能保证内存可见性 3)Volatile不需要加锁,比Synchronized更轻量级,并不会阻塞线程(volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。) 4)volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化(如编译器重排序的优化). 5)volatile是变量修饰符,仅能用于变量,而synchronized是一个方法或块的修饰符。 volatile本质是在告诉JVM当前变量在寄存器中的值是不确定的,使用前,需要先从主存中读取,因此可以实现可见性。而对n=n+1,n++等操作时,volatile关键字将失效,不能起到像synchronized一样的线程同步(原子性)的效果。

【相关习题】

(1)下列说法不正确的是() A.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。 B.当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。 C.当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问不会被阻塞。 D.当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。 答案:C,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将会被阻塞。 (2)下面叙述错误的是: A.通过synchronized和volatile都可以实现可见性 B.不同线程之间可以直接访问其他线程工作内存中的变量 C.线程对共享变量的所有操作都必须在自己的工作内存中进行 D.所有的变量都存储在主内存中 答案:B,不同线程之间无法直接访问其他线程工作内存中的变量

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java多线程之内存可见性和原子性:Synchronized和Volatile的比较
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档