How to make a Java thread wait for another thread's output?
Asked Answered
S

13

138

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 and both need to be running at the same time (one talks to the server, one talks to the user; when the app is fully started, I need both of them to work).

However, on startup, I need to make sure that initially the app thread waits until the db thread is ready (currently determined by polling a custom method dbthread.isReady()). I wouldn't mind if app thread blocks 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.

Sykes answered 14/11, 2008 at 7:29 Comment(0)
C
133

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 is preferably the object that you need to manipulate concurrently from each thread, or you could create a separate Object for that purpose (I would not recommend making the methods themselves 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 are 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.

Chantay answered 14/11, 2008 at 7:56 Comment(5)
Nor all thread code can be nicely integrated in objects, if I am not wrong. So I do not think using object synchronization is a good way to implememnt this thread related work.Attendance
@user1914692: Not sure what pitfalls are there in using the above approach - care to explain further?Sykes
@Piskvor: Sorry I wrote this long time ago and I almost forgot what was on my mind. Maybe I just meant better to use lock, rather than object synchronization, the latter being one simplified form of the former.Attendance
I don't understand how this works. If thread a is waiting on object in synchronised(object) how can another thread go through synchronized(object) to call the object.notifyAll()? In my program, everything just got stuck on synchronozed blocks.Firing
@TomášZato the first thread calls object.wait() effectively unlocking the lock on that object. When the second thread "exits" its synchronized block, then the other objects are released from the wait method and re-obtain the lock at that point.Cosenza
G
150

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();
Gare answered 14/11, 2008 at 9:10 Comment(4)
I really like that solution for it's simplicity, although it might be harder to grasp the code's meaning at first sight.Piecemeal
This usage requires you to remake the latch when they get used up. To get usage similar to a Waitable Event in Windows, you should try a BooleanLatch, or a resettable CountDownLatch: docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… #6596335Dordogne
Hi, if I first call an async method that it supposed to fire an event as such : 1) asyncFunc(); 2) latch.await(); Then I countdown in the event handling function once it is received. How can I make sure that the event won't be handled BEFORE latch.await() is called ? I would like to prevent preemption between line 1 and 2. Thank you.Sophiesophism
To avoid waiting forever in case of errors, put countDown() into a finally{} blockConductance
C
133

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 is preferably the object that you need to manipulate concurrently from each thread, or you could create a separate Object for that purpose (I would not recommend making the methods themselves 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 are 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.

Chantay answered 14/11, 2008 at 7:56 Comment(5)
Nor all thread code can be nicely integrated in objects, if I am not wrong. So I do not think using object synchronization is a good way to implememnt this thread related work.Attendance
@user1914692: Not sure what pitfalls are there in using the above approach - care to explain further?Sykes
@Piskvor: Sorry I wrote this long time ago and I almost forgot what was on my mind. Maybe I just meant better to use lock, rather than object synchronization, the latter being one simplified form of the former.Attendance
I don't understand how this works. If thread a is waiting on object in synchronised(object) how can another thread go through synchronized(object) to call the object.notifyAll()? In my program, everything just got stuck on synchronozed blocks.Firing
@TomášZato the first thread calls object.wait() effectively unlocking the lock on that object. When the second thread "exits" its synchronized block, then the other objects are released from the wait method and re-obtain the lock at that point.Cosenza
M
27

Requirement ::

  1. To wait execution of next thread until previous finished.
  2. Next thread must not start until previous thread stops, irrespective of time consumption.
  3. It must be simple and easy to use.

Answer ::

@See java.util.concurrent.Future.get() doc.

future.get() Waits if necessary for the computation to complete, and then retrieves its result.

Job Done!! See example below

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class ThreadTest {

    public void print(String m) {
        System.out.println(m);
    }

    public class One implements Callable<Integer> {

        public Integer call() throws Exception {
            print("One...");
            Thread.sleep(6000);
            print("One!!");
            return 100;
        }
    }

    public class Two implements Callable<String> {

        public String call() throws Exception {
            print("Two...");
            Thread.sleep(1000);
            print("Two!!");
            return "Done";
        }
    }

    public class Three implements Callable<Boolean> {

        public Boolean call() throws Exception {
            print("Three...");
            Thread.sleep(2000);
            print("Three!!");
            return true;
        }
    }

    /**
     * @See java.util.concurrent.Future.get() doc
     *      <p>
     *      Waits if necessary for the computation to complete, and then
     *      retrieves its result.
     */
    @Test
    public void poolRun() throws InterruptedException, ExecutionException {
        int n = 3;
        // Build a fixed number of thread pool
        ExecutorService pool = Executors.newFixedThreadPool(n);
        // Wait until One finishes it's task.
        pool.submit(new One()).get();
        // Wait until Two finishes it's task.
        pool.submit(new Two()).get();
        // Wait until Three finishes it's task.
        pool.submit(new Three()).get();
        pool.shutdown();
    }
}

Output of this program ::

One...
One!!
Two...
Two!!
Three...
Three!!

You can see that takes 6sec before finishing its task which is greater than other thread. So Future.get() waits until the task is done.

If you don't use future.get() it doesn't wait to finish and executes based time consumption.

Good Luck with Java concurrency.

Maggiore answered 18/1, 2012 at 14:3 Comment(1)
Thank you for your answer! I have used CountdownLatches, but yours is a far more flexible approach.Sykes
S
16

A lot of correct answers but without a simple example.. Here is an easy and simple way how to use CountDownLatch:

//inside your currentThread.. lets call it Thread_Main
//1
final CountDownLatch latch = new CountDownLatch(1);

//2
// launch thread#2
new Thread(new Runnable() {
    @Override
    public void run() {
        //4
        //do your logic here in thread#2

        //then release the lock
        //5
        latch.countDown();
    }
}).start();

try {
    //3 this method will block the thread of latch untill its released later from thread#2
    latch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}

//6
// You reach here after  latch.countDown() is called from thread#2
Selfemployed answered 20/1, 2017 at 12:13 Comment(0)
K
9
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();

EDIT:

(Sorry for editing this post, but this code has a very bad race condition and I don't have enough reputation to comment)

You can only use this if you are 100% sure that signal() is called after await(). This is the one big reason why you cannot use Java object like e.g. Windows Events.

The if the code runs in this order:

Thread 1: resultsReady.signal();
Thread 2: resultsReady.await();

then thread 2 will wait forever. This is because Object.notify() only wakes up one of the currently running threads. A thread waiting later is not awoken. This is very different from how I expect events to work, where an event is signalled until a) waited for or b) explicitly reset.

Note: Most of the time, you should use notifyAll(), but this is not relevant to the "wait forever" problem above.

Kickback answered 11/6, 2009 at 10:21 Comment(0)
R
7

Try 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.

Robertaroberto answered 14/11, 2008 at 7:59 Comment(0)
C
6

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.

Criminology answered 14/11, 2008 at 8:7 Comment(0)
A
4

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.

Arcade answered 14/11, 2008 at 9:0 Comment(0)
A
2

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)
Thread-A waits for lock-b 
Thread-B completes and unlocks lock-b
Arbiter answered 14/11, 2008 at 7:46 Comment(0)
P
2

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.

Pavyer answered 14/11, 2008 at 8:21 Comment(2)
This is pretty much just busy waiting. Using constructs from Java 5's util.concurrent packages should be the way to go. #289934 looks to me as the best solution for now.Gastelum
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 evilBifarious
F
2

You could read from a blocking queue in one thread and write to it in another thread.

Fimbria answered 4/5, 2013 at 15:16 Comment(0)
T
1

Since

  1. join() has been ruled out
  2. you have already using CountDownLatch and
  3. Future.get() is already proposed by other experts,

You can consider other alternatives:

  1. invokeAll from ExecutorService

    invokeAll(Collection<? extends Callable<T>> tasks)
    

    Executes the given tasks, returning a list of Futures holding their status and results when all complete.

  2. ForkJoinPool or newWorkStealingPool from Executors ( since Java 8 release)

    Creates a work-stealing thread pool using all available processors as its target parallelism level.

Tenure answered 10/5, 2016 at 10:24 Comment(0)
A
-1

enter image description here

This idea can apply?. If you use CountdownLatches or Semaphores works perfect but if u are looking for the easiest answer for an interview i think this can apply.

Amoakuh answered 9/5, 2016 at 18:45 Comment(5)
How is this okay for an interview but not for actual code?Sykes
Because in this case is running sequentially one wait for another. The best solution could be using Semaphores because using CountdownLatches that is the best answer given here the Thread never go to sleep which means use of CPU cycles.Amoakuh
But the point wasn't "run them sequentially." I'll edit the question to make this clearer: GUI thread waits until database is ready, and then both run simultaneously for the rest of the app's execution: GUI thread sends commands to DB thread and reads results. (And again: what is the point of code which can be used in an interview but not in actual code? Most technical interviewers I've met had background in code and would ask the same question; plus I needed this thing for an actual app I was writing at the time, not for weaseling through homework)Sykes
So. This is a producer consumer problem using semaphores. I will try to do one exampleAmoakuh
I have created a project github.com/francoj22/SemProducerConsumer/blob/master/src/com/… . It works fine.Amoakuh

© 2022 - 2024 — McMap. All rights reserved.