synchronized的可重入性
-
实例锁和synchronized代码块:
- 当一个对象的实例锁被锁定后,当前线程可以进入该对象的
synchronized
代码块执行同步代码。这意味着在同一时刻,只有一个线程可以执行这个代码块,从而保证了线程安全。
- 当一个对象的实例锁被锁定后,当前线程可以进入该对象的
-
调用另一个synchronized方法:
- 如果在一个
synchronized
代码块中,当前线程又调用了该对象的另一个synchronized
方法,当前线程仍然可以获得锁。这是因为Java的同步机制支持可重入性,也就是说,已经持有锁的线程可以再次进入同一个锁定的代码块或方法。
- 如果在一个
-
子类调用父类的synchronized方法:
- 当一个子类继承自父类时,子类的实例也可以通过可重入锁调用父类的
synchronized
方法。这意味着如果子类的实例已经获得了锁(比如在子类的synchronized
方法中),它可以安全地调用父类的synchronized
方法,而不必担心会导致死锁。
- 当一个子类继承自父类时,子类的实例也可以通过可重入锁调用父类的
-
monitor和计数器:
synchronized
的实现是基于Java的monitor机制。每次一个线程重入同一个锁(即再次请求锁),monitor中的计数器会加1。这意味着线程持有的锁的重入次数会被记录,只有在重入次数减到0时,锁才会被释放。
重入次数怎么减少,是当前线程在synchronized修饰的代码执行完之后吗?
重入次数的减少是由当前线程在synchronized
修饰的代码执行完之后自动完成的。具体来说,以下是重入次数减少的过程:
-
重入计数:
- 当一个线程第一次进入一个
synchronized
代码块或方法时,锁的重入计数器会被设置为1。 - 如果该线程再次进入同一个
synchronized
代码块或方法,计数器会增加到2,以此类推。
- 当一个线程第一次进入一个
-
执行完成:
- 当线程执行完
synchronized
代码块或方法后,重入计数器会减少1。 - 如果重入计数器减到0,表示该线程已经完全退出了所有的
synchronized
代码块或方法,锁会被释放,其他线程就可以获得该锁。
- 当线程执行完
-
线程退出:
- 只有在当前线程退出所有的
synchronized
代码块或方法(即重入计数器减到0)后,锁才会被释放。如果当前线程在一个synchronized
代码块中调用了其他的synchronized
方法,计数器会相应增加,但在退出时仍然会按照相应的次数减少。
- 只有在当前线程退出所有的
总结来说,重入次数的减少确实是在当前线程执行完synchronized
修饰的代码后发生的,只有当重入计数器归零时,锁才会被释放。这样设计的目的是为了确保线程在执行复杂的操作时能够安全地重入同一个锁,避免死锁的情况。