3

给定以下示例: 在此处输入图像描述

这个例子来自“Java Concurrency in Practice”。

有一条评论:

因为 Widget 和 LoggingWidget 中的 doSomething 方法都是同步的,所以在继续之前,它们都会尝试获取 Widget 上的锁。

为什么doSomethingLoggingWidget类中的方法需要获取锁Widget?如果是这样,in 方法的onsynchronized就没用了,对吧?doSomethingLoggingWidget

4

2 回答 2

2

为什么LoggingWidget类中的doSomething方法需要获取Widget的锁?

假设您要确保 2 个线程不能LoggingWidget#doSomething()同时运行(在此示例中,您可能要确保在 print 语句和对 的调用之间没有修改对象super.doSomething()),那么您需要使方法同步.

如果你不这样做,一个线程(T1)可以开始运行LoggingWidget#doSomething()并打印对象,另一个线程(T2)也可以开始运行LoggingWidget#doSomething()(方法不同步)并再次打印对象,然后 T2 可以运行super.doSomething()哪个(假设) 更改对象,然后 T1 将执行super.doSomething(),但对象的状态将不同于它打印的状态,因为 T2 在此期间进行了更改。

防止这种情况的一种方法是使方法同步。

因为 Widget 和 LoggingWidget 中的 doSomething 方法都是同步的,所以在继续之前,它们都会尝试获取 Widget 上的锁。

可重入意味着给定线程可以重新获取它已经持有的锁。在这种情况下,当一个线程进入时,因为方法是同步的LoggingWidget#doSomething(),所以它获取。this当它运行时super.doSomething(),它需要重新获取相同的锁。它的内在锁不是可重入的,线程将永远阻塞在那里,试图获取它已经持有并且不会释放 = 死锁的锁。

于 2012-08-16T11:11:07.470 回答
0

重入锁通过对已经被锁的对象重新获取锁来避免重复。现在,重要的是释放锁不会释放所有的锁。JVM内部维护计数器,每次在对象上获取锁时递增,每次释放锁时递减。因此,这种机制不仅避免了死锁,而且通过保持计数来保持正确性。

于 2012-08-16T11:29:12.703 回答