Synchonized锁的优化

Synchonized锁做了哪些优化?

昨天面试的时候被面试官问到这个问题,但是不够了解,所以在面试结束后查阅资料,在此作下总结。

Synchonized锁的原理以及作用此次不再过多介绍,可以参考此前文章Java多线程及Synchonized关键字

Synchronized锁在JDK1.6的时候做了大量优化,从而实现高效并发,如下:

1、自适应的自旋锁

在原有的Synchronized锁中,如果线程B想要获得object对象的锁,但是发现已经被线程A占有,则会选择阻塞,等到线程A释放锁的时候,线程B被唤醒,再次去尝试获取锁。

因为需要频繁切换后续线程的状态,从而造成一定的性能损失。这时候引入了自旋锁,线程B在发现对象锁已经被A占有的时候,不会立刻进入阻塞,而是进行自旋(循环),在指定自旋次数内,如果A释放了锁,那么B就可以直接去尝试获得锁,不必进行线程状态切换。在达到最大自旋次数后(默认为10),如果A还没有释放,则进入阻塞。因为线程自旋期间也是需要占用系统资源的,如果大量线程在自旋后仍然没有等到释放锁,就会得不偿失。因此自旋锁适用于短任务比较多的场景,同时也可以使用-XX:PreBlockSpin命令设置合理的最大自旋次数。

同时引入了自适应功能,自适应代表着自旋的时间不再固定。线程B等待释放锁的自旋时间,会根据当前占用锁的线程A是否有在自旋期间成功获得锁而动态调整,如果A是在等待释放锁的自旋期间成功获取到了锁,那么就可以认定B也会大概率在自旋期间获得锁,B的自旋时间就会增加。

2、锁消除

锁消除是在虚拟机编译器在运行时候,会将那些代码上要求同步,但是经过检测(逃逸分析和数据支持)不可能存在资源竞争的锁进行消除,从而消除不必要的同步,提高运行效率。

3、锁粗化

在我们日常需要加锁的场景中,总是强调锁的粒度要尽可能小,减少加锁期间的计算量,从而减少单个线程的占锁时间。

大部分情况下这都是对的,但是在一些特殊场景中,比如循环,伪代码如下:

//小粒度锁
for(int a=0;a<100;a++){
    synchronized(this){
        //some sentence
    }
}


//大粒度锁
synchronized(this){
    for(int a=0;a<100;a++){
        //some sentence
    }
}

在上述两个代码中,小粒度锁会因为进行一百次加锁释放锁操作,从而执行效率上没有大粒度锁高。

对此进行锁粗化操作,当虚拟机探测到一系列连续操作都是对同一个对象反复加锁和解锁,就不把加锁同步范围粗化(扩展)到整个操作序列的外围,也就是说上述代码中你实际写的代码是第一种,但是执行结果极大可能是第二种。

同时我们在实际开发过程中,也要根据实际需求,合理设置锁的粒度。

4、轻量级锁

在这里轻量级锁的主要目的是,在没有多线程竞争的前提下,较少传统的重量级锁使用操作系统互斥量产生的性能消耗,实现过程中主要是基于CAS思想,因为过程较为复杂此处不再详细介绍。

ps:CAS是一个很重要的设计思想,在Java的AQS,数据库等乐观锁等,都有应用到CAS设计思想。

5、偏向锁

偏向锁的目的是在数据没有竞争的情况下消除同步操作,

这个偏的偏就是偏心的意思,比如现在占有对象锁的的线程A,那么在线程A释放锁后,没有别的线程来占有锁,那么下次线程A来占有对象锁的时候就不再需要同步操作了,这个偏向锁,偏向的就是上一个占有锁的线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值