views:

132

answers:

4

I have an application that fires 2 threads, the 1st launches another class to do some processing which in turn launches a 3rd class to do yet more processing. The 2nd thread in the main class should wait until some event in the 3rd class completes before it performs its job. How can this be achieved?

I had tried implementing a wait/notify to share a lock object between the two threads but technically this will not work as I found the hard way. Can I share a lock between classes? Note, an instance of the 3rd class is declared in the 1st class and passed as parameter to the 2nd class. Also I tried creating boolean value in 3rd class that tells when event is complete then poll 2nd thread till this value is true. This worked but is not very desirable. Also is actionListner a better approach to this problem?

+3  A: 

What problem did you encounter? As you describe it, it should work. For instance you could implement 2 methods on the 3rd class which keep a flag which is checked from the one and set from the other class using the instance as lock:

boolean done = false;

public synchronized setDone() {

    done = true;

    this.notifyAll();
}

public synchronized waitUntilDone() {

     while (!done) {

        try {
             this.wait();

        } catch (InterruptedException ignore) {
             // log.debug("interrupted: " + ignore.getMessage());
        }
     }
}

(note: typed from memory, not checked using a Java compile)

In principle the this. before the wait and notifyAll is not needed, I find it clearer to include them in this situation.

rsp
Well I do have synchronized methods in the 3rd class but not quite the way you have illustrated. From the first class I start my 2nd thread and in its task method say while(!3rd class.done){ //do nothing } //do processingThe problem I have with my initial outline is use the lock object within the thread task methods and sometimes get deadlocks. I'll try it how your way now. BRB...
Afro Genius
Hi rsp, much thanks for your suggestions. I implemented it and it worked (for a while at least). I still java.nullpointer references on subsequent runs. In my 3rd class I have it just the way you have illustrated which forces the 2nd thread from main class to sleep if !done (in the 2nd threads task method, I call 3rdClass.waitUntilDone immedietly after which I illustrate its task code (give it its job). Is this how I should be specifying it?
Afro Genius
+2  A: 

Use a CountDownLatch with an initial value of 1.

Make the 3rd class call countDown() once processing is complete. The calling thread can then call await(), which will block until processing is complete.

rhys keepence
Great, will give this a go.
Afro Genius
+2  A: 

The problem you are solving can easily be solved by either using ActionListener or using a shared Queue.

Just pick any blocking queue which would block consumer until something comes up in the queue. Simple, clear and proven.

If you need more, look at projects like http://akkasource.org/ or http://jcp.org/en/jsr/detail?id=166 (will be included by default in Java 7).

mindas
+1 for using a blocking queue. However, I'm not sure that using an `ActionListener` helps much with the multi-threading. After all, `ActionListener` is just an interface.
Jim Hurne
A queue is only useful when there are multiple threads producing results. Otherwise, use a Future.If the thread doesn't produce a result, then use a CountDownLatch.BTW JSR-166 was included in Java 1.5.
rhys keepence
Thanx guys for your replies. I will loopk into all these different ideas but the obvious question still remains, which is the best approach?
Afro Genius
@rhys keepence: my apologies, I meant JSR166y
mindas
+1  A: 

You want to use a counting semaphore. Condition variables are meant for scheduling threads inside a monitor. This is not what your trying to do.

You create a counting semaphore and set the count to zero

// create a counting semaphore with an initial count of zero
java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

You pass the semaphore to your class the does the processing. When it is finished, it increasing the count to 1 by calling s.release().

To block a thread until the processor is finished, you call s.aquire(). That call will cause your other thread to block until the processor calls s.release().

This is the simplest solution.

Btw, s.aquire() and s.release() are thread safe, so you don't need to use the synchronize keyword. Threads can share references to a semaphore and call its methods without locking.

UPDATE:

I'm going to respond to your comment here instead of making a new comment.

Yes, in your case a wait()/notify() solution is similar to using a semaphore. To rewrite rsp's solution with a semaphore, it would look like:

java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

public setDone() {
    s.release();
}

public waitUntilDone() {
     s.aquire();
}

It is much simpler and you don't need an unnecessary lock (notice i removed the synchronized keyword from the method decs.).

There are 2 differences between condition variables (wait()/notify()) and semaphores.

Difference #1: calls to notify() may be lost, calls to release() are never lost

The first difference is that calls to notify() are are lost if there is no thread waiting via a call to wait(). The work around is to check the condition before calling wait(). Basically, we need to remember that notify() was called with a shared variable so we don't accidentally call wait() after the worker calls notify(), or else we deadlock. Counting semaphores work no matter the order in which acquire() and release() are called because they maintain a count inside.

Difference #2: calls to wait() automatically release a lock, calls to acquire() do not

Some background information will help here. In your program the boolean done = false; variable is the condition, but it isn't the condition variable. Confusing terminology, I know. The condition variable is the variable that has operations wait() and notify(). Every object in Java has a condition variable hidden inside and a corresponding lock.

All condition variables are associated with a lock. You must acquire the lock before you can call wait() and notify() (you will get a runtime exception if you don't, try it). Once the lock is acquired, calls to wait() automatically release the lock, allowing another thread inside the monitor to possibly call notify(). Sometimes, this is exactly what you want, and trying to simulate this behavior with semaphores will be much more complicated.

Note: I'm using the academic definition of monitor which differs entirely from the Java definition of a monitor.

Jay
Hi, thanx for this answer. Tried it out and works. But works pretty much the same way as using wait and notify on a boolean variable. Guess I'll have to run multiple times to notice any faults. Are they any major differences?
Afro Genius
See the update I made to my awnser.
Jay