views:

18732

answers:

8

Hello,

I'm making a Java application with an application-logic-thread and a database-access-thread. Both of them persist for the entire lifetime of the application. However, I need to make sure that the app thread waits until the db thread is ready (currently determined by calling dbthread.isReady()). I wouldn't mind if app thread blocked until the db thread was ready.

Thread.join() doesn't look like a solution - the db thread only exits at app shutdown.

while (!dbthread.isReady()) {} kind of works, but the empty loop consumes a lot of processor cycles.

Any other ideas? Thanks.

+1  A: 

This applies to all languages:

You want to have an event/listener model. You create a listener to wait for a particular event. The event would be created (or signaled) in your worker thread. This will block the thread until the signal is received instead of constantly polling to see if a condition is met, like the solution you currently have.

Your situation is one of the most common causes for deadlocks- make sure you signal the other thread regardless of errors that may have occurred. Example- if your application throws an exception- and never calls the method to signal the other that things have completed. This will make it so the other thread never 'wakes up'.

I suggest that you look into the concepts of using events and event handlers to better understand this paradigm before implementing your case.

Alternatively you can use a blocking function call using a mutex- which will cause the thread to wait for the resource to be free. To do this you need good thread synchronization- such as:

Thread-A Locks lock-a
Run thread-B
Thread-B waits for lock-a
Thread-A unlocks lock-a (causing Thread-B to continue)
Thraed-A waits for for lock-b 
Thread-B completes and unlocks lock-b
Klathzazt
+15  A: 

I would really recommend that you go through a tutorial like Sun's Java Concurrency before you commence in the magical world of multithreading.

There are also a number of good books out (google for "Concurrent Programming in Java", "Java Concurrency in Practice".

To get to your answer:

In your code that must wait for the dbThread, you must have something like this:

//do some work
synchronized(objectYouNeedToLockOn){
    while (!dbThread.isReady()){
        objectYouNeedToLockOn.wait();
    }
}
//continue with work after dbThread is ready

In your dbThread's method, you would need to do something like this:

//do db work
synchronized(objectYouNeedToLockOn){
    //set ready flag to true (so isReady returns true)
    ready = true;
    objectYouNeedToLockOn.notifyAll();
}
//end thread run method here

The objectYouNeedToLockOn I'm using in these examples are preferable the object that you need to have exclusive access to in each thread, or you could create an Object for that purpose (I would not recommend making the methods synchronized):

private final Object lock = new Object();
//now use lock in your synchronized blocks

To further your understanding: There are other (sometimes better) ways to do the above, e.g. with CountdownLatches, etc. Since Java 5 there area a lot of nifty concurrency classes in the java.util.concurrent package and sub-packages. You really need to find material online to get to know concurrency, or get a good book.

Herman Lintvelt
+3  A: 

Try the CountDownLatch class out of the java.util.concurrent package, which provides higher level synchronization mechanisms, that are far less error prone than any of the low level stuff.

WMR
+2  A: 

You could do it using an Exchanger object shared between the two threads:

private Exchanger<String> myDataExchanger = new Exchanger<String>();

// Wait for thread's output
String data;
try {
  data = myDataExchanger.exchange("");
} catch (InterruptedException e1) {
  // Handle Exceptions
}

And in the second thread:

try {
    myDataExchanger.exchange(data)
} catch (InterruptedException e) {

}

As others have said, do not take this light-hearted and just copy-paste code. Do some reading first.

kgiannakakis
A: 

If you want something quick and dirty, you can just add a Thread.sleep() call within your while loop. If the database library is something you can't change, then there is really no other easy solution. Polling the database until is ready with a wait period won't kill the performance.

while (!dbthread.isReady()) {
  Thread.sleep(250);
}

Hardly something that you could call elegant code, but gets the work done.

In case you can modify the database code, then using a mutex as proposed in other answers is better.

Mario Ortegón
Thread.sleep consumes cpu, Thread.wait does not
dhiller
This is pretty much just busy waiting. Using constructs from Java 5's util.concurrent packages should be the way to go. http://stackoverflow.com/questions/289434/how-to-make-a-java-thread-wait-for-another-threads-output#289567 looks to me as the best solution for now.
Cem Catikkas
It is busy waiting, but if it is only necessary in this particular place, and if there is no access to the db library, what else can you do? Busy waiting is not necessarily evil
Mario Ortegón
+1  A: 

The Future interface from the java.lang.concurrent package is designed to provide access to results calculated in another thread.

Take a look at FutureTask and ExecutorService for a ready-made way of doing this kind of thing.

I'd strongly recommend reading Java Concurrency In Practice to anyone interested in concurrency and multithreading. It obviously concentrates on Java, but there is plenty of meat for anybody working in other languages too.

Bill Michell
+4  A: 

Use a CountdownLatch with a counter of 1.

CountdownLatch latch = new CountdownLatch(1);

Now in the app thread do-

latch.await();

In the db thread, after you are done, do -

latch.countDown();
pdeva
A: 
public class ThreadEvent {

    private final Object lock = new Object();

    public void signal() {
        synchronized (lock) {
            lock.notify();
        }
    }

    public void await() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }
}

Use this class like this then:

Create a ThreadEvent:

ThreadEvent resultsReady = new ThreadEvent();

In the method this is waiting for results:

resultsReady.await();

And in the method that is creating the results after all the results have been created:

resultsReady.signal();