【发布时间】:2013-07-04 07:22:10
【问题描述】:
问题是围绕讨论“Multiple Java threads seemingly locking same monitor”。在我们的应用程序中,我们面临着类似的问题。有时应用程序运行非常缓慢。已捕获多个线程转储。线程转储表明有 2/3 个线程在同一时间点获取了相同的锁对象并处于 BLOCKED 状态。其他线程(在不同时间点有 10 到 20 个)在等待同一个锁对象时被阻塞。伪线程转储如下所示:
"MyThread-91" prio=3 tid=0x07552800 nid=0xc7 waiting for monitor entry [0xc4dff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.myCompany.abc.util.MySharedLinkedList$MySharedIterator.hasNext(MySharedLinkedList.java:177)
- locked <0xce1fb810> (a com.myCompany.abc.util.MySharedLinkedList)
at com.myCompany.abc.util.MyEventProcessor.notifyListeners(MyEventProcessor.java:2644)
...............................................................................................
"MyThread-2" prio=3 tid=0x07146400 nid=0x6e waiting for monitor entry [0xc6aef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.myCompany.abc.util.MySharedLinkedList$MySharedIterator.hasNext(MySharedLinkedList.java:177)
- locked <0xce1fb810> (a com.myCompany.abc.util.MySharedLinkedList)
at com.myCompany.abc.util.MyEventProcessor.notifyListeners(MyEventProcessor.java:2644)
................................................................................................
"MyThread-14" prio=3 tid=0x074b9400 nid=0x7a waiting for monitor entry [0xc64ef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.myCompany.abc.util.MySharedLinkedList$MySharedIterator.next(MySharedLinkedList.java:194)
- waiting to lock <0xce1fb810> (a com.myCompany.abc.util.MySharedLinkedList)
at com.myCompany.abc.util.MyEventProcessor.notifyListeners(MyEventProcessor.java:2646)
................................................................................................
MyThread-91 和 MyThread-2 在锁定 时被阻塞。 MyThread-14 在等待同一个锁 时处于 BLOCKED 状态。
我们肯定没有遇到任何线程死锁问题。请注意,在任何时间点被锁 (0xce1fb810) 阻塞的线程随后都会释放它。但是,其他一些线程在获取相同的锁对象后会被阻塞。根据上面提到的讨论(&sample code 由Gray 提供),这可能是因为在同步块中调用了wait()。但是,我们检查了我们的代码,我们没有看到在同步块中调用了任何 wait()。在我们的例子中,它是链表的内部实现,而链表又具有实现迭代器的内部类。迭代器实现的 next() 和 hasNext() 锁定外部类的同一个实例,即自定义链表的实例。当多个线程调用 next() 和 hasNext() 时,它们在“获取”同一个锁之后进入 BLOCKED 状态。
伪代码如下:
public final class MySharedLinkedList<E> implements Collection<E> {
/**
* Represents an entry in the list.
*/
private static final class Entry<E> {
//Instance variables and methods for Entry goes here.
}
/**
* Non fail-fast implementation of iterator for this list.
*/
public final class MySharedIterator implements Iterator<E> {
public boolean hasNext() {
//Some code goes here.
synchronized (MySharedLinkedList.this) {
//Some code goes here.
}
}
public E next() {
//Some code goes here.
synchronized (MySharedLinkedList.this) {
//Some code goes here.
}
}
}
public synchronized Iterator<E> iterator() {
//Returns a new instance of the iterator.
}
}
/**
* Singleton Instance
*/
public class MyEventProcessor {
//listeners contains a number of Node objects
private final SharedLinkedList<Node> listeners = new SharedLinkedList<Node>();
private void notifyListeners() {
final SharedLinkedList<ProvAPIEventNode>.SharedIterator iterator = listeners.sharedIterator();
try {
while (iterator.hasNext()) {
final Node node = iterator.next();
//Lots of other things go here
} catch (Exception e) {
//Handle the exception
}
}
}
}
那么,问题是还有什么(除了wait())可能导致这种情况?
This blog 谈到了类似的情况(在“示例 2:当处理性能异常缓慢时”部分下)。但不确定这里是否发生了类似的事情。
不要关闭此线程作为this 或this 的副本。如前所述,行为相似,但我想根本原因可能不是。
想法??
【问题讨论】:
-
您没有检查从代码块中调用的每个方法的代码,对吗?等待一定发生在某处。
-
如果您在同步块内的同一监视器上调用
wait()(您确实这样做了,对吗?),这会自动释放锁,因此这不是原因。缺少对 notifyAll() 的调用?另外,一些代码呢?这些是什么显示器?仅同步块、可重入锁、信号量、条件...? -
不,令人惊讶的是我们的代码没有任何等待/通知调用。它是链表的内部实现,而链表又具有实现迭代器的内部类。迭代器实现的 next() 和 hasNext() 锁定外部类的同一个实例,即自定义链表。当多个线程调用 next() 和 hasNext() 时,它们在“获取”同一个锁后进入 BLOCKED 状态。
标签: java multithreading thread-safety thread-dump