Threads : problems with wait() and notify()

Hi,

I'm trying to implement a pause system into a working thread.

In order to make code-reuse, i tried to create an extension of the Thread class like follows:

publicclass ControllableThreadextends Threadimplements Controllable

{

publicenum ThreadActiveStatus{ paused, running};

publicenum ThreadCommand{ start, stop};

private ThreadActiveStatus activeStatus;

private ThreadCommand command;

private Job job;

private ThreadStatusListener listener;

private ExecutionLock lock;

public ControllableThread(ExecutionLock arg0)

{

super();

this.lock = arg0;

this.job =null;

}

publicvoid run()

{

while (true)

{

this.lock.getMonitor();

if (this.job !=null)

{

while (this.command == ThreadCommand.start)

{

// on ns a pas demand?d'arreter, alors, on continue...

this.setActiveStatus(ThreadActiveStatus.running);

this.job.jobRun();

}

//le thread a 閠?mis en pause.

this.setActiveStatus(ThreadActiveStatus.paused);

try

{

this.lock.wait();

}

catch (InterruptedException e){}

}

}

}

privatevoid setActiveStatus(ThreadActiveStatus activeStatus)

{

this.activeStatus = activeStatus;

if (this.listener !=null)

{

this.listener.onThreadStatusUpdate(this.activeStatus);

}

}

public ThreadActiveStatus getActiveStatus()

{

return activeStatus;

}

publicvoid setJob(Job arg0)

{

this.job = arg0;

}

}

ExecutionLock is a very simple object on which i will call wait() and notify().

publicclass ExecutionLock

{

privateint monitorNumber = 0;

public ExecutionLock()

{}

publicsynchronizedvoid getMonitor()

{

this.monitorNumber++;

}

}

The method is completely useless, it's only here to get the monitor (as written here: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#notify()]

So, when i create that thread and start() it, it should be paused.

but " this.lock.wait() " throws IllegalMonitorStateException().

I really can't figure out why i have such an error, as i owned the monitor 13 lines before. Can you tell me where my error lies?

Thanks in advance.

[4708 byte] By [Brzhka] at [2007-11-26 14:37:06]
# 1

> I really can't figure out why i have such an error,

> as i owned the monitor 13 lines before.

No, you own the monitor when your code is being executed within a "synchronized" block. So in order to call x.wait(), the object which x references must be in a synchronized block like this:

synchronized(x)

{

...

x.wait();

...

}

Apparantly you think just because you have a method named "getMonitor" it magically makes you own (and keep) the monitor just by invoking it. As far as the compiler and runtime are concerned, that method may just as well have been named "eatFudge" -- there's no relationship to owning the monitor that the runtime error is talking about.

warnerjaa at 2007-7-8 8:18:03 > top of Java-index,Java Essentials,Java Programming...
# 2

> ExecutionLock is a very simple object on which i will

> call wait() and notify().

>

> public class ExecutionLock

> {

> private int monitorNumber = 0;

> public ExecutionLock()

> {}

>

> public synchronized void getMonitor()

> {

> this.monitorNumber++;

> }

> }

>

> The method is completely useless, it's only here to

> get the monitor (as written here:

> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Obje

> ct.html#notify()]

>

>

>

>

> So, when i create that thread and start() it, it

> should be paused.

> but " this.lock.wait() " throws

> IllegalMonitorStateException().

>

> I really can't figure out why i have such an error,

> as i owned the monitor 13 lines before. Can you tell

> me where my error lies?

> Thanks in advance.

I didn't look through the rest of the code as it's probably irrelevant considering this fundamental misunderstanding. Every instance has a monitor, this includes each instance of Class and each instance of a class. You acquire this monitor using synchronized, however the monitor is also released when you leave the synchronized context or critical section. Hence when you enter the method "getMonitor()" you acquire the monitor to that particular instance of ExecutionLock. However, as soon as you return from "getMonitor()" it is released. It's not persistent, you don't still have the monitor. If you wanted to do that you should use a synchronized block:

synchronized (anyInstanceOfAnObject) {

// do something

}

Wait and notify require you to own the monitor because both of them must release the monitor when they suspend (and reacquire before they resume). You can't release something you don't have and contrary to your belief you do not have the monitor, so you get the exception.

kablaira at 2007-7-8 8:18:03 > top of Java-index,Java Essentials,Java Programming...
# 3
Thanks it's much clearer now =)I just misunderstood the API documentation.
Brzhka at 2007-7-8 8:18:03 > top of Java-index,Java Essentials,Java Programming...