- 什么是可重入,可重入锁?
可重入:(来源于维基百科)若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentrant或re-entrant)的。即当该子程序正在运行时,执行线程可以再次进入并执行它,仍然获得符合设计时预期的结果。与多线程并发执行的线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。
可重入锁:又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的
示例:
public class SynchronizedDemo { public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); demo.method1(); } private synchronized void method1() { System.out.println(Thread.currentThread().getId() + ": method1()"); method2(); } private synchronized void method2() { System.out.println(Thread.currentThread().getId()+ ": method2()"); method3(); } private synchronized void method3() { System.out.println(Thread.currentThread().getId()+ ": method3()"); } }
结合前文中加锁和释放锁的原理,不难理解:
- 执行monitorenter获取锁
- (monitor计数器=0,可获取锁)
- 执行method1()方法,monitor计数器+1 -> 1 (获取到锁)
- 执行method2()方法,monitor计数器+1 -> 2
- 执行method3()方法,monitor计数器+1 -> 3
- 执行monitorexit命令
- method3()方法执行完,monitor计数器-1 -> 2
- method2()方法执行完,monitor计数器-1 -> 1
- method2()方法执行完,monitor计数器-1 -> 0 (释放了锁)
- (monitor计数器=0,锁被释放了)
这就是Synchronized的重入性,即在同一锁程中,每个对象拥有一个monitor计数器,当线程获取该对象锁后,monitor计数器就会加一,释放锁后就会将monitor计数器减一,线程不需要再次获取同一把锁。