views:

135

answers:

3

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!

+1  A: 

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

krtek
Thank you very much!
Albus Dumbledore
+7  A: 

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.

Péter Török
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?
Albus Dumbledore
@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.
Péter Török
"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?
Albus Dumbledore
@Albus, see my update.
Péter Török
@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) { ... }`
Matt Ball
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?
Albus Dumbledore
@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.
Péter Török
@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.
Péter Török
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?
Albus Dumbledore
@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 :-)
Péter Török
Thanks for the _n_ -th time! I think I'll manage now.
Albus Dumbledore
+2  A: 

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.

locka
Yeah, thanks! I hope it won't get to that. After all, good and simple code is always the better solution.
Albus Dumbledore