锁销除、锁粗化

锁销除、锁粗化

锁销除

java中的锁销除是指JVM即时编译器在运行的时候,对一些代码要求同步、但是对被检测到不可能存在共享数据的竞争的锁进行消除。锁销除的主要的依据来源于逃逸机制分析的数据支持、如果判断到一段代码中、在堆上的所有的数据都不会逃逸出去被其它的线程访问到的时候,那么就可以把他们当作栈上的数据对待。栈是线程私有的,也就不会发生线程不安全的问题了。

来看:👇
这是看起来一段没有锁的代码
在这里插入图片描述

但是在JDK5之前字符串的加法操作会转换为StringBuilder对象连续的append()方法来操作、JDK5之后会转换为StringBuffer对象连续的append()方法来操作。StringBuilder和StringBuffer的append()方法区别😄:
来看源码:
StringBuilder调用的是父类的append方法:
在这里插入图片描述
它的父类是AbstractStringBuilder
在这里插入图片描述
来看父类中的append()方法:
在这里插入图片描述

首先StringBuffer也是继承了AbstractStringBuilder类
在这里插入图片描述

StringBuffer重写了父类AbstractStringBuilder的append()方法:👇
在这里插入图片描述
将append()方法变为同步的了。

上图的代码最后会转变为下面的操作:

在这里插入图片描述

使用了synchronized关键来对方法的整体加锁。

在StringBuffer中都有一个同步块、锁的就是StringBuffer对象。虚拟机观察stringBuffer、在经过逃逸分析的时候发现它的动态作用域被限制在concatString()方法的内部。也就是说stringBuffer的所有的引用都不会逃到concatStrng()方法的外部、那也就是其它的线程无法访问到大、所以虽然这里有锁、但是可以被安全的消除掉。在解释执行的时候、这里任然会被加锁、但是经过服务器编译器的即时编译之后、这段代码就会忽略所有的同步的措施而直接执行。

锁粗化

写代码的时候、原则上会将锁的同步代码块的作用的范围限制的尽量的小、只有在共享数据的时候在实际的作用域中才进行同步、目的就是为了减少同步的操作的范围、使程序运行的效率变高。

在大多数的情况之下、这里的原则是正确的。但是如果一系列连续的操作都是对一个对象反复的加锁和解锁、比如加锁是在循环体之中的、那么就是没有线程的竞争、频繁的创建和销毁锁也会导致不必要的性能开销。
比如上面的方法、三个操作都是加锁的操作、那么我们也可以使用一把锁将三个append()方法加锁。

顺提 一下StringBuffer和StringBuilder的区别:
StringBuilder中的方法:
StringBuilder大多调用的是父类AbstractStringBuilder的方法
在这里插入图片描述

StringBuffer:
StringBuffer大多数的方法也是调用的是父类AbstractStringBuilder的方法、但是区别也是显而易见的、StringBuffer的调用父类方法的时候、大都被synchronized关键字修饰、也就是常说的StringBuffer是线程安全的。
在这里插入图片描述

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值