Java.Lang.Illegalmonitorstateexception: Object Not Locked by Thread Before Wait()

java.lang.IllegalMonitorStateException: object not locked by thread before wait()?

This is wrong:

synchronized(foo) {
foo.wait();
}

The problem is, what's going to wake this thread up? That is to say, how do you guarantee that the other thread won't call foo.notify() before the first thread calls foo.wait()? That's important because the foo object will not remember that it was notified if the notify call happens first. If there's only one notify(), and if it happens before the wait(), then the wait() will never return.

Here's how wait and notify were meant to be used:

private Queue<Product> q = ...;
private Object lock = new Object();

void produceSomething(...) {
Product p = reallyProduceSomething();
synchronized(lock) {
q.add(p);
lock.notify();
}
}

void consumeSomething(...) {
Product p = null;
synchronized(lock) {
while (q.peek() == null) {
lock.wait();
}
p = q.remove();
}
reallyConsume(p);
}

The most important things to to note in this example are that there is an explicit test for the condition (i.e., q.peek() != null), and that nobody changes the condition without locking the lock.

If the consumer is called first, then it will find the queue empty, and it will wait. There is no moment when the producer can slip in, add a Product to the queue, and then notify the lock until the consumer is ready to receive that notification.

On the other hand, if the producer is called first, then the consumer is guaranteed not to call wait().

The loop in the consumer is important for two reasons: One is that, if there is more than one consumer thread, then it is possible for one consumer to receive a notification, but then another consumer sneaks in and steals the Product from the queue. The only reasonable thing for the fist consumer to do in that case is wait again for the next Product. The other reason that the loop is important is that the Javadoc says Object.wait() is allowed to return even when the object has not been notified. That is called a "spurious wakeup", and the correct way to handle it is to go back and wait again.

Also note: The lock is private and the queue is private. That guarantees that no other compilation unit is going to interfere with the synchronization in this compilation unit.

And note: The lock is a different object from the queue itself. That guarantees that synchronization in this compilation unit will not interfere with whatever synchronization that the Queue implementation does (if any).


NOTE: My example re-invents a wheel to prove a point. In real code, you would use the put() and take() methods of an ArrayBlockingQueue which would take care of all of the waiting and notifying for you.

Object not locked by thread before wait in Android app on Non Activity

Here´s Question about a similar Issue. It might be usefull

in short from top answer:

Quote: "Here's how wait and notify were meant to be used:"

private Queue<Product> q = ...;
private Object lock = new Object();

void produceSomething(...) {
Product p = reallyProduceSomething();
synchronized(lock) {
q.add(p);
lock.notify();
}
}

void consumeSomething(...) {
Product p = null;
synchronized(lock) {
while (q.peek() == null) {
lock.wait();
}
p = q.remove();
}
reallyConsume(p);
}

Object not locked by thread before wait in Android app

When you call wait() inside a class, you are actually calling wait() on the current instance of that class. To do that, it requires a lock on that instance. If another thread has the lock, you will not be able to wait.

Adding synchronized to onCreate() will acquire the lock (the current instance of the Activity) and let you call wait() inside, but this is definitely not want you want to do as it will block the main/UI thread and cause your app to be non-responsive.

What you probably want instead is the following inside your activity:

private boolean isTerminationConditionMet = false;

@Override
public void onCreate() {
//standard Android onCreate code

final Handler handler = new Handler();
final Runnable task = new Runnable() {
@Override
public void run() {
//code you want to run every second
if (!isTerminationConditionMet()) {
handler.postDelayed(task, 1000);
}
}
}
handler.postDelayed(task, 1000);
}

This will cause the code inside run() to be run after the desired delay (1000ms) and then every 1000 ms until your termination condition is met.

Android java.lang.IllegalMonitorStateException: object not locked by thread before wait()

A common replacement for wait/notify is CountDownLatch. (From java.util.concurrent as well but working kind of inverse of Semaphore - see answer by Tom)

You initialize it to the amount of steps required, threads that have finished count down and some other place waits for the countdown to reach 0.

void doFoo() {
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable() {

@Override
public void run() {
//this is a http request
appSignInfo = getAPKSignature(context, pkinfo.packageName);
latch.countDown();
}
}).start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

if (appSignInfo == null) {
return ret;
}
}

But the code you wrote there can be simplified to

void doFoo() {
return getAPKSignature(context, pkinfo.packageName);
}

You start a second thread to do something and all you do in that time is to wait. If there is nothing to do while that task is running don't create an extra thread. The result is the same.

If you try to do a HTTP request outside of the UI thread because you get that NetworkOnMainThreadExcpeption, you have to do it differently. While Android won't detect your code as long time blocking code it still is. Use an AsyncTask for example.

CountDownLatch: object not locked by thread before wait()

You are using the wrong method. You should call await, not wait. See CountDownLatch for example code.



Related Topics



Leave a reply



Submit