给出以下示例:
这个例子来自“Java Concurrency in Practice”。
有评论:
因为Widget和LoggingWidget中的doSomething方法都是同步的,所以每个方法都会在继续之前尝试获取Widget上的锁。
为什么LoggingWidget类中的方法doSomething
需要获取Widget
上的锁?如果是,synchronized
中方法doSomething
上的LoggingWidget
无用,对吗?
答案 0 :(得分:2)
为什么LoggingWidget类中的doSomething方法需要获取Widget上的锁?
假设您要确保2个线程不能同时运行LoggingWidget#doSomething()
(在此示例中,您可能希望确保在print语句和对{{{}的调用之间未修改对象1}}),然后你需要使方法同步。
如果不这样做,线程(T1)可以开始运行super.doSomething()
并打印对象,另一个线程(T2)也可以开始运行LoggingWidget#doSomething()
(该方法未同步)和再次打印对象,然后T2可以运行LoggingWidget#doSomething()
(让我们说)更改对象,然后T1将执行super.doSomething()
但对象的状态将与打印的不同,因为T2已经在此期间发生了变化。
防止这种情况的一种方法是使方法同步。
因为Widget和LoggingWidget中的doSomething方法都是同步的,所以每个方法都会在继续之前尝试获取Widget上的锁。
可重入意味着给定的线程可以重新获取它已经拥有的锁。在这种情况下,当线程进入super.doSomething()
时,它会获取LoggingWidget#doSomething()
,因为该方法是同步的。当它运行this
时,它需要重新获取相同的锁。内在锁不是可重入的,线程会永远阻塞它,试图获取它已经存在的锁并且它不会释放=死锁。
答案 1 :(得分:0)
重入锁定将通过重新获取已锁定的对象的锁定来避免重复。现在,重要的是释放锁定不会释放所有锁定。 JVM内部维护计数器,每次在对象上获取锁定时计数器将递增,并在每次锁定释放时递减。因此,这种机制不仅可以避免死锁,还可以通过保持计数来保持正确性。