Albus Dumbledore Albus Dumbledore - 1 month ago 14
Java Question

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 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!

Answer

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.

Comments