Dead-locks in Java: When they occur?
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 f开发者_开发问答ollowing 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!
Would, for instance, calling a synchronized method of a object cause dead lock if it calls another synchronized method of its own?
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 underlying Lock
object itself is not visible in the code, only the object we are locking on. Consider
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
}
}
}
Both the synchronizedOnThis*
methods are synchronized on the containing MyClass
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 its synchronizedOnThis*
methods, that call will block as long as this thread is within the synchronized(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.
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.
See this: http://www.herongyang.com/Java/Deadlock-What-Is-Deadlock.html
when does deadlock occur?
Excessive usage of synchronization with inconsistent lock ordering causes deadlock.
Solution to avoid dead lock
Maintain the order and use less of synchronization.
The following is one scenario, which makes deadlock.
public void method1() {
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
}
}
}
public void method2() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
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.
public void method1() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
public void method2() {
synchronized (Integer.class) {
System.out.println("Aquired lock on Integer.class object");
synchronized (String.class) {
System.out.println("Aquired lock on String.class object");
}
}
}
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
精彩评论