jdk锁知识(二)——volatile、synchronized

1、volatile与synchronized的异同点

1)volatile与synchronized都是java的关键字,且都具有内存可见性

2)synchronized具有内存可见性和原子性,不能禁止指令重排,但是通过as-if-serial语义(所有硬件的优化都必须遵守as-if-serial语义)可以保证程序执行的有序性。

3)volatile仅用于修饰变量,synchronized可以修饰变量、方法、代码块

2、volatile主要功能是什么、实现原理是什么

volatile是happen-before八大原则中的一条,在先行原则中定义,如果先写volatile修饰的变量,再读volatile修饰的变量,那么读操作一定在写操作之后。它所具有的功能是禁止指令重排以及保证内存可见性。

volatile之所以能实现这两个功能,主要是依赖内存屏障来实现(反编译class文件可以看到,内存屏障本质是一组cpu指令)。这里禁止指令重排好理解,因为编译器和处理器为了能更快的运行代码,所以它们会在一定程度上重新排列程序执行的顺序,当我们加入内存屏障后,就可以避免编译器处理器对屏障内的指令执行顺序做出修改。内存可见性这个要想理解,首先要知道工作内存和主内存的概念(不知道的话可以浏览该系列第一篇文章),当我们对工作内存中的变量做出修改后,volatile修改的变量会立刻刷新到主内存,从而被其它共用该变量的线程感知到。

3、synchronized主要功能是什么,其是如何实现的

synchronized具有锁的功能,可以保证内存可见性原子性,注意这里有一个指令重排的误解,那就是误以为该关键字可以禁止指令重排,其实该关键字不具备禁止指令重排的功能。但它可以通过as-if-serial语义保证程序执行的有序性。

synchronized实现锁功能时,主要是通过锁定对象来实现的。这个锁定的对象和new的对象其实是有区别的。我们new的对象的对象头分为mark word和Kclass两部分,mark word包含了对象的hashcode还有锁定状态等信息,实际锁定的就是这个mark word部分。

另外通过反编译后的字节码可以看到synchronized功能的实现主要有两种方式:

1)同步代码块采用monitorenter、monitorexit指令显式的实现。

1)同步方法则使用ACC_SYNCHRONIZED标记符隐式的实现

4、synchronized优化过程

jdk1.6之前synchronized是一个重量级的锁,使用较少,之后被优化后,在不同场景下有不同的锁选择。下面是锁大致的优化过程:

无锁:当只有一个线程时是无锁状态,此时通过CAS乐观锁实现资源竞争获取

偏向锁:一个资源总被同一线程访问,那么对象头会记录该线程ID,竞争获取锁时直接判断该线程是否与存储的线程ID相同

轻量级锁:偏向锁状态下,又有一个线程竞争资源,如果正好上一个线程释放资源,此时仍是偏向锁,如果没释放资源,则新来线程自旋等待,偏向锁升级为轻量级锁

重量级锁:轻量级锁状态下如果又有第三个竞争线程访问、或者轻量级锁状态下自旋超过一定次数升级为重量级锁

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值