sync为啥是重量级锁?

此篇文章写的比较杂乱,自己总结的一些碎片知识。

jdk1.6及以前,synchronized关键字修饰方法是一个重量级锁的操作

内置锁synchronized与显式锁Lock

解释为什么jdk1.6以前synchronized是重量级锁,性能低下的原因?

为啥是重量级锁?

在这个版本之前,加锁的操作是涉及到操作系统进行互斥操作,就是会把当前线程挂起,然后操作系统进行互斥操作修改,由mutexLock来完成,之后才唤醒。操作系统来判断线程是否加锁,所以它是一个重量级操作挂起、唤醒这两个操作进行了两次上下文切换,消耗CPU,降低性能。其实在这个版本之前已经考虑到CAS操作,但是默认是没有开启的。

当然,除了操作系统维护锁的状态使当前线程挂起外,只要是synchronized,一有竞争也会引起阻塞,阻塞和唤醒操作又涉及到了上下文操作,大量消耗CPU,降低性能。

总之一句话,重量级锁是需要依靠操作系统来实现互斥锁的,这导致大量上下文切换,消耗大量CPU,影响性能。

 

ReentrantLock为啥产生?

就是因为synchronized性能低,有人就开发了ReentrantLock,大大提高了性能,其中涉及到了AQS高并发组件,用它来维护锁的状态等,这样就不需要利用操作系统来维护,减少上下文切换,做到了基本在Java级别上就能完成操作。里面还用了CAS,自旋等操作来提高性能。但是线程过多的话,还是避免不了和操作系统打交道,就是阻塞和唤醒这两个上下文操作消耗资源。

 

什么是上下文操作?

线程多,不断阻塞、唤醒:一次阻塞+唤醒操作需要两次上下文切换,就是第一次由用户态切换到内核态,由内核将线程阻塞掉,将线程数据原本在寄存器或者cache运送到内存或队列中,第二次由用户态切换到内核态,由内核将线程唤醒,将线程数据从内存或者队列送到寄存器或cache中。如果频繁进行上下文切换,CPU就大多数消耗在内核数据共享中,影响了真正工作线程功能

上下文切换过高会导致CPU像个搬运工,频繁在寄存器和运行队列之间奔波 ,更多的时间花在了线程切换,而不是真正工作的线程上。直接的消耗包括CPU寄存器需要保存和加载,系统调度器的代码需要执行。间接消耗在于多核cache之间的共享数据。
 

jdk1.6后Synchronized的优化

引入了无锁、偏向锁、轻量级锁、重量级锁等等

jdk1.6之前的synchronized是上锁就要调用os方法,上下文切换导致性能低,1.6之后出现偏向锁、、一般在java级别就解决了锁的问题

这里简单分析下优化过程

偏向锁是用ThreadId来表示偏向锁开启状态,并且在对象头就记录了当前线程。当存在线程竞争时,就会检查是不是当前线程,不是就说明有竞争,升级锁为轻量级锁。

轻量级锁,不需要操作系统中来维护互斥锁了,CAS操作修改当前对象头中MarkWord的指向就可以完成上锁。

多竞争时导致产重量级锁。

注意:高并发量大时,sync效率比CAS效率要高。但是一般情况下sync效率比CAS要低,因为sync是重量级锁操作

 

推荐一篇好的文章:https://www.cnblogs.com/javaminer/p/3889023.html

猜你喜欢

转载自blog.csdn.net/qq_41055045/article/details/102646117