143

I have an object with a method named StartDownload(), that starts three threads.

How do I get a notification when each thread has finished executing?

Is there a way to know if one (or all) of the thread is finished or is still executing?

Jeroen Mostert
  • 27,176
  • 2
  • 52
  • 85
Ricardo Felgueiras
  • 3,589
  • 6
  • 25
  • 27
  • 1
    Take a look at the Java 5 [Barrier class](http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html) – Fortyrunner Mar 31 '09 at 19:00

12 Answers12

249

There are a number of ways you can do this:

  1. Use Thread.join() in your main thread to wait in a blocking fashion for each Thread to complete, or
  2. Check Thread.isAlive() in a polling fashion -- generally discouraged -- to wait until each Thread has completed, or
  3. Unorthodox, for each Thread in question, call setUncaughtExceptionHandler to call a method in your object, and program each Thread to throw an uncaught Exception when it completes, or
  4. Use locks or synchronizers or mechanisms from java.util.concurrent, or
  5. More orthodox, create a listener in your main Thread, and then program each of your Threads to tell the listener that they have completed.

How to implement Idea #5? Well, one way is to first create an interface:

public interface ThreadCompleteListener {
    void notifyOfThreadComplete(final Thread thread);
}

then create the following class:

public abstract class NotifyingThread extends Thread {
  private final Set<ThreadCompleteListener> listeners
                   = new CopyOnWriteArraySet<ThreadCompleteListener>();
  public final void addListener(final ThreadCompleteListener listener) {
    listeners.add(listener);
  }
  public final void removeListener(final ThreadCompleteListener listener) {
    listeners.remove(listener);
  }
  private final void notifyListeners() {
    for (ThreadCompleteListener listener : listeners) {
      listener.notifyOfThreadComplete(this);
    }
  }
  @Override
  public final void run() {
    try {
      doRun();
    } finally {
      notifyListeners();
    }
  }
  public abstract void doRun();
}

and then each of your Threads will extend NotifyingThread and instead of implementing run() it will implement doRun(). Thus when they complete, they will automatically notify anyone waiting for notification.

Finally, in your main class -- the one that starts all the Threads (or at least the object waiting for notification) -- modify that class to implement ThreadCompleteListener and immediately after creating each Thread add itself to the list of listeners:

NotifyingThread thread1 = new OneOfYourThreads();
thread1.addListener(this); // add ourselves as a listener
thread1.start();           // Start the Thread

then, as each Thread exits, your notifyOfThreadComplete method will be invoked with the Thread instance that just completed (or crashed).

Note that better would be to implements Runnable rather than extends Thread for NotifyingThread as extending Thread is usually discouraged in new code. But I'm coding to your question. If you change the NotifyingThread class to implement Runnable then you have to change some of your code that manages Threads, which is pretty straightforward to do.

Eddie
  • 53,828
  • 22
  • 125
  • 145
  • 4
    but using this approach, the notifiyListeners is called inside the run() so it will be called insisde the thread and the further calls will be done there too, isn't it this way? – Jordi Puigdellívol Mar 15 '13 at 10:03
  • @Jordi Puigdellivol: I don't understand your question. – Eddie Apr 08 '13 at 17:19
  • 1
    @Eddie Jordi was asking, if it's possible to call `notify` method not insinde the `run` method, but after it. – Tomasz Dzięcielewski Jun 06 '13 at 05:49
  • 2
    The question really is: how do you get **OFF** of the secondary thread now. I know that it's finished, but how do I access the **Main** thread now? – avalancha Aug 28 '13 at 13:42
  • avalancha: It depends on what you mean by getting off the secondary thread. As soon as the secondary thread doRun() method ends, that thread is done. It's not running any more. The main thread, on the other hand, is still running. What do you want to do, exactly? @TomasDz: It's not possible to do anything after the run() method completes. Once that method completes, the thread is no longer running, so it cannot cause anything to happen. – Eddie Sep 23 '13 at 15:26
  • I don't see how to implement notifyOfThreadComplete. I don't know how to make the implementation of the interface effective. Could someone apport a hint about this? – Alex Nov 18 '13 at 17:50
  • @Alex: If your main class, you may have notifyOfThreadComplete count the number of calls (on an AtomicInteger for example) and when you hit the correct number of calls, you know every thread has completed. – Eddie Nov 22 '13 at 23:44
  • This worked wonderfully well! Spent half a day for going around asyncTask, and ended up with this solution. Really cool! – olleh Jan 03 '18 at 14:10
  • 2
    Is this thread safe? It appears that notifyListeners (and thus notifyOfThreadComplete) will be called within the NotifyingThread, rather than within the thread that created created the Listener itself. – Aaron Mar 02 '18 at 03:56
14

Solution using CyclicBarrier

public class Downloader {
  private CyclicBarrier barrier;
  private final static int NUMBER_OF_DOWNLOADING_THREADS;

  private DownloadingThread extends Thread {
    private final String url;
    public DownloadingThread(String url) {
      super();
      this.url = url;
    }
    @Override
    public void run() {
      barrier.await(); // label1
      download(url);
      barrier.await(); // label2
    }
  }
  public void startDownload() {
    // plus one for the main thread of execution
    barrier = new CyclicBarrier(NUMBER_OF_DOWNLOADING_THREADS + 1); // label0
    for (int i = 0; i < NUMBER_OF_DOWNLOADING_THREADS; i++) {
      new DownloadingThread("http://www.flickr.com/someUser/pic" + i + ".jpg").start();
    }
    barrier.await(); // label3
    displayMessage("Please wait...");
    barrier.await(); // label4
    displayMessage("Finished");
  }
}

label0 - cyclic barrier is created with number of parties equal to the number of executing threads plus one for the main thread of execution (in which startDownload() is being executed)

label 1 - n-th DownloadingThread enters the waiting room

label 3 - NUMBER_OF_DOWNLOADING_THREADS have entered the waiting room. Main thread of execution releases them to start doing their downloading jobs in more or less the same time

label 4 - main thread of execution enters the waiting room. This is the 'trickiest' part of the code to understand. It doesn't matter which thread will enter the waiting room for the second time. It is important that whatever thread enters the room last ensures that all the other downloading threads have finished their downloading jobs.

label 2 - n-th DownloadingThread has finished its downloading job and enters the waiting room. If it is the last one i.e. already NUMBER_OF_DOWNLOADING_THREADS have entered it, including the main thread of execution, main thread will continue its execution only when all the other threads have finished downloading.

cdbbnny
  • 330
  • 2
  • 9
Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148
9

You should really prefer a solution that uses java.util.concurrent. Find and read Josh Bloch and/or Brian Goetz on the topic.

If you are not using java.util.concurrent.* and are taking responsibility for using Threads directly, then you should probably use join() to know when a thread is done. Here is a super simple Callback mechanism. First extend the Runnable interface to have a callback:

public interface CallbackRunnable extends Runnable {
    public void callback();
}

Then make an Executor that will execute your runnable and call you back when it is done.

public class CallbackExecutor implements Executor {

    @Override
    public void execute(final Runnable r) {
        final Thread runner = new Thread(r);
        runner.start();
        if ( r instanceof CallbackRunnable ) {
            // create a thread to perform the callback
            Thread callerbacker = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // block until the running thread is done
                        runner.join();
                        ((CallbackRunnable)r).callback();
                    }
                    catch ( InterruptedException e ) {
                        // someone doesn't want us running. ok, maybe we give up.
                    }
                }
            });
            callerbacker.start();
        }
    }

}

The other sort-of obvious thing to add to your CallbackRunnable interface is a means to handle any exceptions, so maybe put a public void uncaughtException(Throwable e); line in there and in your executor, install a Thread.UncaughtExceptionHandler to send you to that interface method.

But doing all that really starts to smell like java.util.concurrent.Callable. You should really look at using java.util.concurrent if your project permits it.

broc.seib
  • 21,643
  • 8
  • 63
  • 62
  • I'm a little unclear on what you gain from this callback mechanism vs simply calling `runner.join()` and then whatever code you want after that, since you know the thread has finished. Is it just that you get to define that code as a property of the runnable, so you could have different things for different runnables? – Stephen Mar 24 '18 at 00:23
  • 2
    Yes, `runner.join()` is the most direct way to wait. I was assuming the OP didn't want to block their main calling thread since they asked to be "notified" for each download, which could complete in any order. This offered one way to get notified asynchronously. – broc.seib Mar 24 '18 at 14:28
4

Many things have been changed in last 6 years on multi-threading front.

Instead of using join() and lock API, you can use

1.ExecutorService invokeAll() API

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

2.CountDownLatch

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.

3.ForkJoinPool or newWorkStealingPool() in Executors is other way

4.Iterate through all Future tasks from submit on ExecutorService and check the status with blocking call get() on Future object

Have a look at related SE questions:

How to wait for a thread that spawns it's own thread?

Executors: How to synchronously wait until all tasks have finished if tasks are created recursively?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
4

You could also use the Executors object to create an ExecutorService thread pool. Then use the invokeAll method to run each of your threads and retrieve Futures. This will block until all have finished execution. Your other option would be to execute each one using the pool and then call awaitTermination to block until the pool is finished executing. Just be sure to call shutdown() when you're done adding tasks.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
J Gitter
  • 49
  • 1
4

Do you want to wait for them to finish? If so, use the Join method.

There is also the isAlive property if you just want to check it.

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • 3
    Note that isAlive returns false if the thread hasn't started executing yet (even if your own thread has already called start on it). – Tom Hawtin - tackline Mar 31 '09 at 18:52
  • @TomHawtin-tackline are you quite sure about that? It would contradict the Java documentation ("A thread is alive if it has been started and has not yet died" - https://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#isAlive%28%29). It would also contradict the answers here (https://stackoverflow.com/questions/17293304/when-is-a-java-thread-alive) – Stephen Mar 23 '18 at 22:37
  • @Stephen A long time since I wrote that, but it seems to be true. I imagine it caused other people problems that were fresh in my memory nine years ago. Exactly what is observable will depend upon implementation. You tell a `Thread` to `start`, which the thread does, but the call returns immediately. `isAlive` should be a simple flag test, but when I googled it the method was `native`. – Tom Hawtin - tackline Mar 25 '18 at 21:33
4

You can interrogate the thread instance with getState() which returns an instance of Thread.State enumeration with one of the following values:

*  NEW
  A thread that has not yet started is in this state.
* RUNNABLE
  A thread executing in the Java virtual machine is in this state.
* BLOCKED
  A thread that is blocked waiting for a monitor lock is in this state.
* WAITING
  A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
* TIMED_WAITING
  A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
* TERMINATED
  A thread that has exited is in this state.

However I think it would be a better design to have a master thread which waits for the 3 children to finish, the master would then continue execution when the other 3 have finished.

Miquel
  • 4,741
  • 3
  • 20
  • 19
  • Waiting for the 3 children to exit may not fit in the usage paradigm. If this is a download manager, they may want to start 15 downloads and simply remove status from the status bar or alert the user when a download has completed, in which case a callback would work better. – digitaljoel Mar 31 '09 at 18:47
3

I guess the easiest way is to use ThreadPoolExecutor class.

  1. It has a queue and you can set how many threads should be working in parallel.
  2. It has nice callback methods:

Hook methods

This class provides protected overridable beforeExecute(java.lang.Thread, java.lang.Runnable) and afterExecute(java.lang.Runnable, java.lang.Throwable) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated() can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.

which is exactly what we need. We will override afterExecute() to get callbacks after each thread is done and will override terminated() to know when all threads are done.

So here is what you should do

  1. Create an executor:

    private ThreadPoolExecutor executor;
    private int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();    
    
    
    
    private void initExecutor() {
    
    executor = new ThreadPoolExecutor(
            NUMBER_OF_CORES * 2,  //core pool size
            NUMBER_OF_CORES * 2, //max pool size
            60L, //keep aive time
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>()
    ) {
    
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
                //Yet another thread is finished:
                informUiAboutProgress(executor.getCompletedTaskCount(), listOfUrisToProcess.size());
            }
        }
    
    };
    
        @Override
        protected void terminated() {
            super.terminated();
            informUiThatWeAreDone();
        }
    
    }
    
  2. And start your threads:

    private void startTheWork(){
        for (Uri uri : listOfUrisToProcess) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    doSomeHeavyWork(uri);
                }
            });
        }
        executor.shutdown(); //call it when you won't add jobs anymore 
    }
    

Inside method informUiThatWeAreDone(); do whatever you need to do when all threads are done, for example, update UI.

NOTE: Don't forget about using synchronized methods since you do your work in parallel and BE VERY CAUTIOUS if you decide to call synchronized method from another synchronized method! This often leads to deadlocks

Hope this helps!

Kirill Karmazin
  • 6,256
  • 2
  • 54
  • 42
2

I would suggest looking at the javadoc for Thread class.

You have multiple mechanisms for thread manipulation.

  • Your main thread could join() the three threads serially, and would then not proceed until all three are done.

  • Poll the thread state of the spawned threads at intervals.

  • Put all of the spawned threads into a separate ThreadGroup and poll the activeCount() on the ThreadGroup and wait for it to get to 0.

  • Setup a custom callback or listener type of interface for inter-thread communication.

I'm sure there are plenty of other ways I'm still missing.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
digitaljoel
  • 26,265
  • 15
  • 89
  • 115
1

Here's a solution that is simple, short, easy to understand, and works perfectly for me. I needed to draw to the screen when another thread ends; but couldn't because the main thread has control of the screen. So:

(1) I created the global variable: boolean end1 = false; The thread sets it to true when ending. That is picked up in the mainthread by "postDelayed" loop, where it is responded to.

(2) My thread contains:

void myThread() {
    end1 = false;
    new CountDownTimer(((60000, 1000) { // milliseconds for onFinish, onTick
        public void onFinish()
        {
            // do stuff here once at end of time.
            end1 = true; // signal that the thread has ended.
        }
        public void onTick(long millisUntilFinished)
        {
          // do stuff here repeatedly.
        }
    }.start();

}

(3) Fortunately, "postDelayed" runs in the main thread, so that's where in check the other thread once each second. When the other thread ends, this can begin whatever we want to do next.

Handler h1 = new Handler();

private void checkThread() {
   h1.postDelayed(new Runnable() {
      public void run() {
         if (end1)
            // resond to the second thread ending here.
         else
            h1.postDelayed(this, 1000);
      }
   }, 1000);
}

(4) Finally, start the whole thing running somewhere in your code by calling:

void startThread()
{
   myThread();
   checkThread();
}
0

You could also use SwingWorker, which has built-in property change support. See addPropertyChangeListener() or the get() method for a state change listener example.

akarnokd
  • 69,132
  • 14
  • 157
  • 192
0

Look at the Java documentation for the Thread class. You can check the thread's state. If you put the three threads in member variables, then all three threads can read each other's states.

You have to be a bit careful, though, because you can cause race conditions between the threads. Just try to avoid complicated logic based on the state of the other threads. Definitely avoid multiple threads writing to the same variables.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286