一、如果想要了解 synchronized 是如何运⾏的?就要先搞清楚 synchronized 是如何实现?
一、如果想要了解 synchronized 是如何运⾏的?就要先搞清楚 synchronized 是如何实现?
synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的而监视器⼜是依赖操作系统的互斥锁 Mutex 实现的在 HotSpot 虚拟机中,Monitor 底层是由 C++实现的
二、监视器
监视器是⼀个概念或者说是⼀个机制,它⽤来保障在任何时候,只有⼀个线程能够执⾏指定区域的代码。
下面我们来通过一段代码的演示查看监视器:
public class ThreadSynchronized5 {
public static void main(String[] args) {
synchronized (ThreadSynchronized5.class){
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
}
下面是她的字节码文件:
由此可知 synchronized 是依赖 Monitor 监视器实现的。
监视器的执行流程:
监视器执⾏的流程描述如下:
1. 线程通过 CAS(对⽐并替换)尝试获取锁,如果获取成功,就将 _owner 字段设置为当前线程,说明当前线程已经持有锁,并将 _recursions 重⼊次数的属性 +1 。如果获取失败则先通过⾃旋 CAS尝试获取锁,如果还是失败则将当前线程放⼊到 EntryList 监控队列(阻塞)。2. 当拥有锁的线程执⾏了 wait ⽅法之后,线程释放锁,将 owner 变量恢复为 null 状态,同时将该线程放⼊ WaitSet 待授权队列中等待被唤醒。3. 当调⽤ notify ⽅法时,随机唤醒 WaitSet 队列中的某⼀个线程,当调⽤ notifyAll 时唤醒所有的WaitSet 中的线程尝试获取锁。4. 线程执⾏完释放了锁之后,会唤醒 EntryList 中的所有线程尝试获取锁。
三、简要概述非公平锁和公平锁
在Java中,Synchronized是非公平锁,也是可重入锁
我们先来介绍一下公平锁:一定要执行的步骤:
1.上一个线程释放锁之后执行唤醒
2.最前面的线程从阻塞状态又切换到运行状态
那么我们在简要的概述一下非公平锁,我们的非公平锁并不需要在执行的时候进行排队等待,只要该线程再来的时候占用锁资源的线程刚好释放锁,那么该线程就可以立刻执行,而不需要等待排序。
四、总结(Synchronized详细执行流程)
synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的,⽽监视器⼜是依赖操作系统的互斥锁Mutex 实现的。JVM 监视器的执⾏流程是:线程先通过⾃旋 CAS 的⽅式尝试获取锁,如果获取失败就进⼊ EntrySet 集合,如果获取成功就拥有该锁。当调⽤ wait() ⽅法时,线程释放锁并进⼊ WaitSet 集合,等其他线程调⽤ notify 或 notifyAll ⽅法时再尝试获取锁。锁使⽤完之后就会通知 EntrySet 集合中的线程,让它们尝试获取锁。