Java synchronized可重入锁的底层实现(新手必看)
可重入锁也称为递归锁,在同一线程内,外层函数获得该锁之后,内层递归函数仍然可以获取到该锁。这种锁在同一线程内是安全的,因为它可以被同一线程多次获取,而不会产生不一致的状态。
可重入锁的意义之一在于防止死锁。一个线程在已经持有锁的情况下,再次请求该锁,如果锁是不可重入的,那么该线程在第二次请求锁时将被阻塞,因为它已经拥有了该锁。在这种情况下,该线程可能会因为无法获取该锁而导致程序发生死锁。可重入锁通过允许一个线程多次获取同一个锁,保证了线程的执行不会被阻塞,从而避免了死锁问题。
synchronized 是可重入锁吗?我们先看一个示例,具体代码如下:
在 Java 内部,当同一个线程调用自己类中其他 synchronized 方法或代码块时不会阻碍该线程的执行,同一个线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,即可以多次重入。
通过上面的详解我们知道了 synchronized 是可重入锁,那么可重入锁的实现原理是什么呢?
要知道,每个对象都有一个关联的 Monitor,Monitor 有一个计数器,当一个线程要进入 synchronized 代码块时,需要先判断 Monitor 的计数器的值是否为 0,如果该值为 0 表示该锁没有被任何线程持有,线程可以获得该锁并调用相应方法。
当一个线程请求成功后,Monitor 会记下持有锁的线程,并将计数器的值记为 1。此时其他线程如果请求该锁,则必须等待,而持有锁的线程如果再次请求这个锁,就可以再次获取,同时计数器会递增 1。当线程退出一个 synchronized 方法或代码块时,Monitor 的计数器的值就会递减 1,直到该值为 0 时才释放该锁。
通过上述过程,我们知道 synchronized 可重入锁的实现原理与 synchronized 的底层实现原理是不可分割的,都是通过锁对象的 Monitor 及其计数器的值递增或递减进行控制的,同一个线程对同一个对象的 Monitor 是可以多次重入的,重入时计数器的值递增 1,退出时再递减 1,直到计数器的值为 0 时释放锁,在此期间其他任何线程的访问都会被阻塞。
可重入锁的意义之一在于防止死锁。一个线程在已经持有锁的情况下,再次请求该锁,如果锁是不可重入的,那么该线程在第二次请求锁时将被阻塞,因为它已经拥有了该锁。在这种情况下,该线程可能会因为无法获取该锁而导致程序发生死锁。可重入锁通过允许一个线程多次获取同一个锁,保证了线程的执行不会被阻塞,从而避免了死锁问题。
synchronized 是可重入锁吗?我们先看一个示例,具体代码如下:
public class SynchronizedLockTest { public static void main(String[] args) { new SynchronizedLock().m1(); } } class SynchronizedLock { static Object lock = new Object(); public void m1() { synchronized (lock) { System.out.println("m1外层执行!"); m2(); } } public void m2() { synchronized (lock) { System.out.println("m2中层执行!"); m3(); } } public void m3() { synchronized (lock) { System.out.println("m3内层执行!"); } } }示例代码执行结果如下所示:
m1外层执行!
m2中层执行!
m3内层执行!
在 Java 内部,当同一个线程调用自己类中其他 synchronized 方法或代码块时不会阻碍该线程的执行,同一个线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,即可以多次重入。
通过上面的详解我们知道了 synchronized 是可重入锁,那么可重入锁的实现原理是什么呢?
要知道,每个对象都有一个关联的 Monitor,Monitor 有一个计数器,当一个线程要进入 synchronized 代码块时,需要先判断 Monitor 的计数器的值是否为 0,如果该值为 0 表示该锁没有被任何线程持有,线程可以获得该锁并调用相应方法。
当一个线程请求成功后,Monitor 会记下持有锁的线程,并将计数器的值记为 1。此时其他线程如果请求该锁,则必须等待,而持有锁的线程如果再次请求这个锁,就可以再次获取,同时计数器会递增 1。当线程退出一个 synchronized 方法或代码块时,Monitor 的计数器的值就会递减 1,直到该值为 0 时才释放该锁。
通过上述过程,我们知道 synchronized 可重入锁的实现原理与 synchronized 的底层实现原理是不可分割的,都是通过锁对象的 Monitor 及其计数器的值递增或递减进行控制的,同一个线程对同一个对象的 Monitor 是可以多次重入的,重入时计数器的值递增 1,退出时再递减 1,直到计数器的值为 0 时释放锁,在此期间其他任何线程的访问都会被阻塞。