views:

1269

answers:

8

I have one object that have one method named StartDownload(), that starts three threads. How do I make to get a notification when each thread as finished the execution?

Is there a way to know in one of the threads if one of the other two is finished or is still executing?

+3  A: 

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
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
A: 

Look at the java docs 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.

Don Kirkby
A: 

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
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
+2  A: 

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
Hi!! I like the last idea. I to implement a listener to do that? Thanks
arpf
I updated my answer to add a code example.
Eddie
A: 

I would suggest looking at the javadoc for the Thread class.

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html

In there, 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.

digitaljoel
+3  A: 

Take a look at the Java 5 Barrier class

Fortyrunner
+1  A: 

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

Boris Pavlović
A: 

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

kd304