Dead-locks in Java: When they occur?
Asked Answered
R

4

10

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!

Roby answered 30/8, 2010 at 8:9 Comment(0)
V
12

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.

Vinculum answered 30/8, 2010 at 8:16 Comment(9)
Do you mean to say that all synchronized methods of an object would use the same lock so no dead-lock would be possible to arise?Roby
@Albus, declaring a method synchronized is equivalent to enclosing the method contents in a synchronized(this) block. I.e. all synchronized instance methods lock on the same class instance, so no deadlock is possible. Unless, of course, someone else outside the object locks on the same object.Damle
"Unless, of course, someone else outside the object locks on the same object." Well, one can't do that if the Lock object is not exposed manually by me, can one?! That is, if all synchronization is done through synchronized methods, there is no such danger, is there?Roby
@Albus: no, that isn't the case - "someone else outside the object locks on the same object" meaning someone outside of a MyClass method calls MyClass foo = new MyClass(); ... synchronized(foo) { ... }Trustless
Thanks so much! So, would you say that using private objects as a lock, would be a safer approach than the synchronized(this) one? If so, would it be a design concern, if I still synch the entire source of the method as there are quite a few things to update?Roby
@Albus, it is theoretically safer, albeit it makes the code a bit more complicated. Well written code shouldn't contain such problematic locks anyway, so it is more a question of style (or paranoia :-) The only case where I would definitely use this idiom is a public library where I have no control over client code.Damle
@Albus, when syncing the whole method body, the biggest concern is how long the execution may take. Long held locks increase the chance of thread contention, and thus may slow down execution significantly, to say the least. Whether to use a synchronized(someObject) block or a synchronized method is a minor concern to me in this context.Damle
Well, the last two answers are actually pretty obvious, when I come to think of it, but for them I feel more confident in my thinking. Thanks! Bad though that I still can't point the problem: I have a Canvas and external events access it through synchronized methods of that canvas. So, after all said, it can't possibly be a deadlock, right?Roby
@Albus, if you only have a single lock in the game, there can't be deadlock. Note however, that there may be hidden locks involved in library calls, especially when GUI is involved. I don't know J2ME so I can't say anything specific about it. I suggest you open a new question and show the relevant part of your code - surely there are J2ME experts over here :-)Damle
C
2

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.

Casals answered 30/8, 2010 at 8:26 Comment(1)
Yeah, thanks! I hope it won't get to that. After all, good and simple code is always the better solution.Roby
M
1

See this: http://www.herongyang.com/Java/Deadlock-What-Is-Deadlock.html

Morrismorrison answered 30/8, 2010 at 8:11 Comment(0)
S
0

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

Shakiashaking answered 30/6, 2015 at 6:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.