Java 中的死锁:什么时候发生?
我正在为 J2ME 开发一个应用程序,有时它会完全冻结,并且 AMS 需要相当长的时间来关闭它。在我看来,这就像一个僵局问题。
您能告诉我什么可能导致死锁吗?例如,如果调用对象的同步方法调用其自己的另一个同步方法,是否会导致死锁?
谢谢!
更新
我说的对吗,在以下情况下应该会发生死锁:
对象 P 调用对象 A 的同步方法,即调用对象 B 的同步方法,该方法调用对象 A 的同步方法
抱歉,如果我看起来很愚蠢,很可能确实如此。但这就是我问的原因。谢谢!
I am working on an app for the J2ME and sometime it freezes completely and it takes quite some time for the AMS to close it. It seems to me like a dead-lock issue.
Could you advise me as to what could cause dead locks? Would, for instance, calling a synchronized method of a object cause dead lock if it calls another synchronized method of its own?
Thanks!
Update
Am I right in saying that a deadlock is supposed to happen in the following case:
Object P calls a synch method of object A, that calls a synch method of object B, that calls a synch method of object A
Sorry if it looks stupid of me, most probably it is. But that's why I'm asking. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不会,因为 Java 中的
同步
锁是可重入的:您可以从同一个线程多次获取同一个锁,不会出现问题。例如,当线程 A 持有锁 L 并尝试获取锁 M,而线程 B 持有锁 M 并尝试获取锁 L 时,就会发生死锁。因此,两个线程都在等待对方持有的锁,并且无法释放它们的锁。自己的锁。这会导致两个线程永远等待。这种情况也可能涉及 2 个以上的线程。
死锁可能很难检测到,因此典型的方法是通过仔细设计来尝试避免死锁。实现此目的的最简单方法是确保任何要获取多个锁的线程始终以相同的预定义全局顺序获取它们。例如,如果在上面的示例中,线程 A 和 B 都尝试先获取锁 L,然后获取锁 M,则不会出现死锁。
您的问题也可能是由死锁以外的其他原因引起的,例如活锁(当一个线程虽然没有被阻止,但仍然无法进行时,因为它不断重试总是失败的操作)。
更新:从对象外部访问锁
使用Java内部锁(即同步块),底层的Lock对象本身在代码中不可见,只有我们所在的对象锁定。考虑
synchronizedOnThis*
方法在包含的MyClass
实例上同步;两种方法的同步是等效的。但是,类实例显然可以被外部世界访问,因此外部方可以将其用作类外部的锁,如上所示。如果该对象可从另一个线程访问,并且该线程调用其synchronizedOnThis*
方法之一,则只要该线程位于synchronized(myObject)
内,该调用就会阻塞> 阻止。OTOH 方法
synchronizedOnPrivateObject
使用私有对象作为锁。如果该对象未以任何方式发布给外部各方,则任何其他人都不能(无意或恶意)导致涉及此锁的死锁。No, because
synchronized
locks in Java are reentrant: you can acquire the same lock from the same thread multiple times without a problem.A deadlock occurs e.g. when thread A holds lock L and tries to acquire lock M, while thread B holds lock M and tries to acquire lock L. Thus both threads are waiting for a lock held by the other, and can not progress to release their own lock. This causes both threads to wait forever. The situation may be involving more than 2 threads as well.
Deadlocks can be very difficult to detect, so the typical way is to try to avoid them by careful design. The simplest means to achieve this is to ensure that any thread which is to acquire multiple locks, acquires them always in the same predefined global order. E.g. if in the above example both threads A and B attempt to acquire lock L first, then lock M, there will be no deadlock.
Your issue may be caused by other things than a deadlock too, e.g. a livelock (when a thread, while not blocked, still can't progress because it keeps retrying an operation that always fails).
Update: accessing the lock from outside the object
With Java intrinsic locks (i.e.
synchronized
blocks), the underlyingLock
object itself is not visible in the code, only the object we are locking on. ConsiderBoth the
synchronizedOnThis*
methods are synchronized on the containingMyClass
instance; the synchronization of the two methods is equivalent. However, the class instance is obviously accessible to the outside world, so an external party can use it as a lock from outside the class, as shown above. And if the object is accessible from another thread, and that thread calls one of itssynchronizedOnThis*
methods, that call will block as long as this thread is within thesynchronized(myObject)
block.OTOH the method
synchronizedOnPrivateObject
uses a private object as lock. If that object is not published to external parties in any way, noone else can (inadvertently or malevolently) cause a deadlock involving this lock.最可能的原因是两个线程试图获取两个对象的锁。线程 1 锁定 A 并正在等待 B,但线程 2 锁定 B 并正在等待 A。两个线程最终都会永远等待永远不会被释放的对象。
除了确保您的代码按照定义明确的顺序执行操作之外,没有快速的解决方案。作为一般规则,同步块应尽可能小,通常在特定对象上而不是在方法上。进行大量登录,看看是否可以确定是否发生了类似的情况。
Java 5 有显式的 Lock 对象,它允许更细粒度的控制,包括简单同步块的超时,但我不知道它们对 J2ME 是否有用。有一个 Java 5 并发库的向后移植,可以与 J2ME 一起使用 - http:// backport-jsr166.sourceforge.net/ 如果这个问题足够大,值得使用它们。
Most probable reason would be two threads trying to obtain locks to two objects. Thread 1 locks A and is waiting for B, but thread 2 locks B and is waiting for A. Both threads end up waiting forever for objects which will never be released.
There is no quick solution except make sure your code does things in a very well defined order. As a general rule, the synchronized block should be as small as possible, usually on a specific object than on a method. Put a lot of logging in and see if you can figure out if something like this is happening.
Java 5 has explicit Lock objects which allow a finer grained control including timeouts over simple synchronized blocks but I do not know if they would be useful for J2ME. There is a backport of the Java 5 concurrency libs which it may be possible to get working with J2ME - http://backport-jsr166.sourceforge.net/ if this issue is sufficiently large to merit using them.
看看这个:
http://www.herongyang.com/Java/Deadlock-What- Is-Deadlock.html
See this:
http://www.herongyang.com/Java/Deadlock-What-Is-Deadlock.html
过度使用锁顺序不一致的同步会导致死锁。
维护顺序,少用同步。
以下是一种导致死锁的场景。
如果 method1() 和 method2() 都将被两个或多个线程调用,则很可能会出现死锁,因为如果线程 1 在执行 method1() 时获取 Sting 对象上的锁,而线程 2 在执行 method2 时获取 Integer 对象上的锁() 两者都将等待对方释放对 Integer 和 String 的锁定以进一步进行,但这永远不会发生。
如果您仔细查看了上面的代码,您可能已经发现死锁的真正原因不是多线程而是它们访问锁的方式,如果您提供有序访问那么问题就会得到解决,这是修复版本。
现在不会有任何死锁,因为这两种方法都以相同的顺序访问 Integer 和 String 对象上的锁。因此,如果线程 A 获取了 Integer 对象的锁,则线程 B 将不会继续执行,直到线程 A 释放 Integer 锁,同样,即使线程 B 持有 String 锁,线程 A 也不会被阻塞,因为现在线程 B 不会期望线程 A 释放 Integer 锁继续进行。
礼貌
Excessive usage of synchronization with inconsistent lock ordering causes deadlock.
Maintain the order and use less of synchronization.
The following is one scenario, which makes deadlock.
If method1() and method2() both will be called by two or many threads , there is a good chance of deadlock because if thead 1 aquires lock on Sting object while executing method1() and thread 2 acquires lock on Integer object while executing method2() both will be waiting for each other to release lock on Integer and String to proceed further which will never happen.
if you have looked above code carefully you may have figured out that real reason for deadlock is not multiple threads but the way they access lock , if you provide an ordered access then problem will be resolved , here is the fixed version.
Now there would not be any deadlock because both method is accessing lock on Integer and String object in same order . so if thread A acquires lock on Integer object , thread B will not proceed until thread A releases Integer lock , same way thread A will not be blocked even if thread B holds String lock because now thread B will not expect thread A to release Integer lock to proceed further.
Courtesy