Sychronized实现原理

Sychronized使用java对象作为锁(锁的状态保存在java对象头部)。

使用sychronized可以保证在同一时刻只能有一个线程进入同步代码,并保证共享变量对其他线程的可见性。

1.说到实现原理这里先介绍一下内置锁和互斥锁:

内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁。在退出的时候会释放该锁。获得内置锁的唯一途径就是进入这个锁保护的同步代码块会方法中。

互斥锁:内置锁是通过互斥锁实现的,也就是说某一个时刻最多只有一个线程能够持有该锁,当线程A尝试去获得线程B所持有的内置锁时,线程A必须等待线程B释放锁,此时线程A处于一个等待或阻塞状态。

在JDK1.6以前sychronized是重量级锁,sychronized的实现是通过java对象的监视器(minitor)实现的,而监视器又依赖于底层操作系统的MutexLock(互斥锁)。线程间的切换时,操作系统会从用户态转换成核心态,成本比较高,耗时长,所以sychronized使用起来效率比较低。

2.JDK1.6以后,做了优化增加了从偏向锁->轻量级锁->重量级锁的过度(锁的升级是单向不可逆的,只能从低到高)。

各种锁适应的环境

偏向锁:只有一个线程,尽量减少不必要的轻量级锁执行路径。

轻量锁:出现多个线程交替执行代码块,当多次尝试占时用轻量级锁失败的时候,轻量级锁会膨胀为重量级锁,通过自旋来获得重量级锁

重量锁:和轻量级锁差不多,但是不会使用自旋锁。

3.为什么用自旋锁,什么是自旋锁?

减少线程状态改变带来的损耗,频繁的阻塞和唤醒对cpu来说是一个负担很重的工作,自旋锁就是让线程等待一段时间,不会立即被挂起,看持有锁的线程是否会很快的释放锁,从而检查线程状态的切换。如何自旋,就是让线程执行一段无意义的循环,如果自旋结束后恰好持有锁的线程释放了锁,在这种理想状态下,自旋的效率的非常好。如果并不理想,长时间的自旋会浪费资源反而影响性能。所以自旋要有个度,在JDK1.6就引用了适应性自旋锁来处理这个问题

4.什么是适应性自旋锁?

适应性自旋锁就是自旋的次数不固定,自旋的次数会根据前一个在该锁上自旋的时间和拥有者的状态来变动。假设上一个在自旋线程成功了,那么我就会认为这一次自旋线程也是很有可能会成功,我就不介意让这个线程再多等一会,增加自旋的次数。相反对于某个锁来说,很少有线程自旋能够成功的获得锁,那我就觉得线程在这等的结果也不会比前面的那些线程好到哪去,就不要浪费时间在这自旋了,相应的就减少线程自旋的次数或者直接跳过自旋不浪费处理器的资源。

5.synchronized的使用

修饰普通方法:锁住对象实例

修饰静态方法:锁住整个类

修饰代码块:锁住一个对象 synchronized(lockObject) 也就是lockObject

本博客有参考其他博客的相关信息  Sychronized的底层实现原理以及各种锁的理解  我总结的比较笼统,要是想深入了解的话。可以看这篇

猜你喜欢

转载自blog.csdn.net/sinat_36265222/article/details/86529194