synchronized和volatile关键字学习笔记

synchronized和volatile关键字学习笔记

在用java实现多线程场景时,经常能看见synchronized和volatile关键字的使用,但二者在原理及使用场景不尽相同。

先放结论:
1、synchronized关键字对对象加锁,能确保线程安全,但较影响性能;
2、volatile关键字实现两个功能:内存可见性及防止指令重排;无法确保线程安全;

synchronized:
用来修饰代码块或方法,锁分为对象锁和类锁;修饰实例方法时为对象锁,修饰静态方法时为类锁;修饰代码块时,根据传入的数据判断是什么类型的锁(若传入this或对象引用,则未对象锁;若传入XXX.class对象的类类型对象,则为类锁)。

加锁方式:无锁–>偏向锁–>轻量级锁–>重量级锁

锁膨胀:由低级锁升级到高级锁,不可逆向降级;

锁粗化:试想有一个循环,循环里面是一些敏感操作,有的人就在循环里面写上了synchronized关键字。这样确实没错不过效率也许会很低,因为其频繁地拿锁释放锁。要知道锁的取得(假如只考虑重量级MutexLock)是需要操作系统调用的,从用户态进入内核态,开销很大。于是针对这种情况也许虚拟机发现了之后会适当扩大加锁的范围(所以叫锁粗化)以避免频繁的拿锁释放锁的过程。

锁消除:通过逃逸分析发现其实根本就没有别的线程产生竞争的可能(别的线程没有临界量的引用),而“自作多情”地给自己加上了锁。有可能虚拟机会直接去掉这个锁。

具体原理可参见:https://www.cnblogs.com/aspirant/p/11470858.html

volatile:
用来修饰变量,volatile变量执行时不会有加锁的操作,因此并不能保证线程安全

内存可见性:JVM定义了在java应用的工作过程中分为主内存和工作内存,主内存是所有线程共享的,工作内存为线程私有内存,线程在使用主内存中的变量时,并不是直接在主内存中读取,而是将主内存的变量复制到工作内存的缓存中。此时会出现如下情况:
当线程A要将主内存中的变量a加1时,将a复制缓存进工作内存,加1后将其刷新回主内存,但是在此期间,若有线程B也读取了a,B有可能读取了就旧的a数据,导致线程A、B有一者的操作无效。若给a加上volatile关键字,则当线程A对变量a进行写操作时,会将其他线程中变量a的缓存无效,其他线程必需从主内存中重新读取,实现了内存可见性。

防止jvm进行指令优化重排:加了volatile修饰的变量,jvm会在变量前后加上内存屏障,阻止指令的重排序。

可参考:https://baijiahao.baidu.com/s?id=1663045221235771554&wfr=spider&for=pc
https://www.cnblogs.com/zhengbin/p/5654805.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值