欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > synchronized的详解、锁的升级过程和优缺点比较

synchronized的详解、锁的升级过程和优缺点比较

2025/3/12 9:30:24 来源:https://blog.csdn.net/m0_73864806/article/details/142283925  浏览:    关键词:synchronized的详解、锁的升级过程和优缺点比较

本文 详细介绍Java中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁轻量级 锁、重量级锁,以及锁升级过程。

Java中每一个对象都可以作为锁。具体表现形式为以下三种形式:

  • 对于普通的同步方法,锁是当前的实例对象
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是Synchronized括号里面的配置对象

演示:

Person类中的代码:

package com.qcby.demo1;public class Person {public int age;public String name;public int[] arr = {1,2,3};public String[] arr2 = {"aaa","bbb"};public Person son;//锁对象public synchronized void m1(){System.out.println("我是m1开始");try{Thread.sleep(4000);}catch(InterruptedException e){}System.out.println("我是m1结束");}//锁对象public  synchronized void m2(){System.out.println("我是m2开始");try{Thread.sleep(4000);}catch(InterruptedException e){}System.out.println("我是m2结束");}//锁类public synchronized static void m3(){System.out.println("我是m3开始");try{Thread.sleep(4000);}catch (InterruptedException e){}System.out.println("我是m3结束");}//锁类public synchronized static void m4(){System.out.println("我是m4开始");try{Thread.sleep(4000);}catch (InterruptedException e){}System.out.println("我是m4结束");}}

Test类中的代码:

package com.qcby.demo1;public class Test {public static void main(String[] args) {System.out.println("阿瑟东");Person ww = new Person();Thread x1 = new Thread() {@Overridepublic void run(){ww.m1();}};Thread x2 = new Thread() {@Overridepublic void run(){ww.m2();}};Thread x3 = new Thread(){@Overridepublic void run(){ww.m3();}};Thread x4 = new Thread(){@Overridepublic void run(){ww.m4();}};x1.start();x2.start();x3.start();x4.start();}}

结果展示:

1、调用同一个对象中的m1、m2方法时:

m2方法会等待m1方法结束之后才能开启

2、调用不同对象中的m1、m2方法时:

m1和m2方法几乎同时开启,同时结束

3、调用同一个类中的m3、m4方法时:

m4方法会等待m3方法结束之后才能开启

锁的升级和对比:

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是由同 一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁

当一个线程访问同步块并且获取锁的时候,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块的时候不需要进行CAS操作来加锁和解锁,只需要测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

  • 如果测试成功,表示线程已经获得了锁
  • 如果测试失败,则需 要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁)
    • 如果没有设置,则 使用CAS竞争锁;
    • 如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

偏向锁的撤销:偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放锁。

轻量级锁

当两个或以上的线程交替获取锁,但并没有在对象上并发的获取锁时,偏向锁升级为轻量级锁。在此阶段,线程采取CAS的自旋方式尝试获取锁,避免阻塞线程造成CPU在用户态和内核态间转换的消耗。

重量级锁

因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级 成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时, 都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮 的夺锁之争。

三种锁的优缺点的对比:

优点

缺点

适用场景

偏向锁

加锁和不加锁不需要额外的消耗,和事项非同步方法相比只存在纳秒级别的差距。

如果线程之间存在锁的竞争,会带来额外的锁撤销的消耗

适用于只有一个线程访问同步块场景

轻量级锁

竞争的线程不会阻塞,提高了程序的响应速度

如果一直得不到锁竞争的线程,适用自旋回消耗CPU

追求响应时间,同步块执行速度非常快

重量级锁

线程竞争不适用自旋,不会消耗CPU

线程阻塞,响应时间缓慢

追求吞吐量,同步块执行速度比较长

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词