我正在为J2ME开发一个应用程序,有时它会完全冻结,关闭AMS需要相当长的时间。在我看来这是个死锁的问题。
你能告诉我什么会导致死锁吗?例如,如果对象调用自己的另一个同步方法,那么调用对象的同步方法会导致死锁吗?
谢谢!
更新
我说得对吗?在以下情况下,僵局应该发生:
对象P调用对象A的同步方法,该方法调用对象B的同步方法,调用对象A的同步方法
抱歉,如果我看起来很蠢,很可能是。但这就是为什么我要问。谢谢!
发布于 2010-08-30 08:16:54
例如,如果对象调用自己的另一个同步方法,那么调用对象的同步方法会导致死锁吗?
不,因为synchronized锁在Java中是可重入的:您可以多次从同一个线程获得相同的锁,而不会出现问题。
当线程A持有锁L并试图获得锁M时,当线程B持有锁M并试图获取锁L时,就会发生死锁。因此,两个线程都在等待另一个线程持有的锁,并且无法释放自己的锁。这将导致两个线程永远等待。这种情况也可能涉及两个以上的线程。
死锁很难检测,所以典型的方法是通过精心设计来避免死锁。实现这一目标的最简单方法是确保任何要获取多个锁的线程始终以相同的预定义全局顺序获得锁。例如,在上面的示例中,如果线程A和B都试图先获得锁L,然后锁定M,则不会出现死锁。
您的问题可能也是由死锁以外的其他因素引起的,例如,一个活锁(当一个线程虽然没有被阻塞,但仍然不能继续运行,因为它一直在重新尝试一个总是失败的操作)。
Update:从对象外部访问锁
使用Java内部锁(即synchronized块),底层的Lock对象本身在代码中是不可见的,只有我们锁定的对象。考虑一下
class MyClass {
private Object object = new Object();
public synchronized void synchronizedOnThis1() {
...
}
public void synchronizedOnThis2() {
synchronized(this) {
...
}
}
public void synchronizedOnPrivateObject() {
synchronized(object) {
...
}
}
}
class ExternalParty {
public void messUpLocks() {
final MyClass myObject = new MyClass();
synchronized(myObject) {
Thread otherThread = new Thread() {
public void run() {
myObject.synchronizedOnThis1();
}
};
otherThread.start();
// do a lengthy calculation - this will block the other thread
}
}
}两个synchronizedOnThis*方法在包含的MyClass实例上都是同步的;这两个方法的同步是等价的。但是,类实例显然对外部世界是可访问的,因此外部方可以使用它作为来自类外部的锁,如上面所示。如果可以从另一个线程访问对象,并且该线程调用其synchronizedOnThis*方法之一,则只要该线程位于synchronized(myObject)块内,该调用就会阻塞。
OTOH方法synchronizedOnPrivateObject使用私有对象作为锁。如果该对象没有以任何方式发布给外部各方,则没有其他人(无意中或恶意地)会导致涉及此锁的死锁。
发布于 2010-08-30 08:26:15
最可能的原因是两个线程试图获得两个对象的锁。线程1锁定A并等待B,但线程2锁定B并等待A,这两个线程最终都将永远等待永远不会释放的对象。
除了确保您的代码按照非常明确的顺序执行之外,没有任何快速解决方案。通常情况下,同步块应该尽可能小,通常是在特定对象上,而不是在方法上。输入大量的日志,看看你是否能弄清楚这样的事情是否正在发生。
Java5有显式锁定对象,允许更细粒度的控制,包括对简单同步块的超时,但我不知道它们对J2ME是否有用。Java 5并发库有一个后端,如果这个问题大到值得使用,就可以使用J2ME - http://backport-jsr166.sourceforge.net/。
发布于 2010-08-30 08:11:13
https://stackoverflow.com/questions/3598822
复制相似问题