synchronized底层原理,关于无锁、偏向锁、轻量级锁、重量级锁问题 public static void main(String[] args) throws InterruptedException { //HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式 Thread.sleep(5000); Object obj = new Object(); System.out.println("匿名偏向状态 =====================" + "\n" + ClassLayout.parseInstance(obj).toPrintable()); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "thread-a").start(); // 这段代码未注释时会出现两种结果: // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->偏向锁(线程B) // 结果2:初始化偏向锁(未偏向)-->偏向锁(线程A)->轻量级锁(线程B)->无锁 // 代码注释也会有两种结果: // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->重量级锁(线程B)->无锁 // 结果2:初始化偏向锁(未偏向)-->重量级锁(线程A)->重量级锁(线程B)->无锁 Thread.sleep(1000); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "thread-b").start(); // 睡眠5s后 Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + ClassLayout.parseInstance(obj).toPrintable()); } "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20240926/36c8b455a317ffcfbf565d2546616756.png) "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20240926/18d7f6294010efed90d1025cc2a539f9.png) Thread.sleep(1000); // 这段代码未注释时会出现两种结果: // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->偏向锁(线程B) // 结果2:初始化偏向锁(未偏向)-->偏向锁(线程A)->轻量级锁(线程B)->无锁 // 代码注释也会有两种结果: // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->重量级锁(线程B)->无锁 // 结果2:初始化偏向锁(未偏向)-->重量级锁(线程A)->重量级锁(线程B)->无锁 **以上代码JDK版本1.8** 看了网上很多视频和文章的分析,总结下来是大多数讲的没那么深,而且有一些细节地方每篇文章可能分析的都不一样,参考那些技术的分析还是没有弄懂为什么会产生这几种不同的结果,底层的锁升级逻辑到底是怎样的呢,有没有大佬帮忙仔细分析下呢,如果能带着一起看源码那最好了......
Java 实现单例模式有方法有双重检测锁,代码如下: public class Singleton { private static volatile Singleton singleton = null; private Singleton(){} public static Singleton getSingleton(){ if(singleton == null){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } } 我理解的 synchronized 关键字实现了可见性、原子性和有序性,临界区中的代码可以重排序,但是不能重排序到临界区外面,synchronized 实现的可见性是临界区中代码执行结束之后,里面的共享变量会刷新到主内存中,那么如果 new Singleton() 方法被拆成了三个操作,并且经过重排序之后的顺序是这样的话: 1. 分配内存 2. 将实例引用赋值给 singleton 变量 3. 实例初始化 不管这三个操作怎么重排序,另外一个线程看到的结果都是这三个操作执行完成后的结果(因为 synchronized 的原子性),那不就相当于另外一个线程访问到的 singleton 如果不为 null 的话就肯定实例化了吗?为什么还要多此一举加个 volatile 关键字禁止重排序呢?