How to Know If Other Threads Have Finished

How to know if other threads have finished?

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.

How to check if the threads have completed its task or not?

A good way to use threads is not to use them, directly. Instead make a thread pool. Then in your POJO task encapsulation have a field that is only set at the end of computation.

There might be 3-4 milliseconds delay when another thread can see the status - but finally the JVM makes it so. As long as other threads do not over write it. That you can protect by making sure each task has a unique instance of work to do and status, and other threads only poll that every 1-5 seconds or have a listener that the worker calls after completion.
A library I have used is my own
https://github.com/tgkprog/ddt/tree/master/DdtUtils/src/main/java/org/s2n/ddt/util/threads

To use : in server start or static block :

package org.s2n.ddt.util;

import org.apache.log4j.Logger;
import org.junit.Test;

import org.s2n.ddt.util.threads.PoolOptions;
import org.s2n.ddt.util.threads.DdtPools;

public class PoolTest {
private static final Logger logger = Logger.getLogger(PoolTest.class);

@Test
public void test() {
PoolOptions options = new PoolOptions();
options.setCoreThreads(2);
options.setMaxThreads(33);
DdtPools.initPool("a", options);
Do1 p = null;
for (int i = 0; i < 10; i++) {
p = new Do1();
DdtPools.offer("a", p);

}
LangUtils.sleep(3 + (int) (Math.random() * 3));
org.junit.Assert.assertNotNull(p);
org.junit.Assert.assertEquals(Do1.getLs(), 10);
}

}

class Do1 implements Runnable {
volatile static long l = 0;

public Do1() {
l++;

}

public void run() {

// LangUtils.sleep(1 + (int) (Math.random() * 3));
System.out.println("hi " + l);
}

public static long getLs() {
return l;
}
}

Things you should not do:
* Don't do things every 10-15 milliseconds
* Unless academic do not make your own thread
* don't make it more complex then it needs for 97% of cases

How to check if Thread finished execution

Use the Thread.IsAlive flag. This is to give the thread status.

How to check if thread is terminated?

First: Thread.getState() returns a Thread.State, which will never be equal to a String, so you'd need to write that code like this:

if(thread.getState()!=Thread.State.TERMINATED){ }

And yes: when the run() method ends (either normally or because it throws an exception), then a Thread will go to the TERMINATED state.

How to know if a set of threads has finished

It's very unclear to me what you are really trying to accomplish, so it's hard to recommend a best practice.

But for what you are asking, doing a thread.Join() on every thread that you start will ensure that you wait for all threads to complete.

See .NET 2.0 doc: https://msdn.microsoft.com/en-us/library/95hbf2ta(v=vs.80).aspx

Your code would then look something like this:

Private Sub xTask(ByVal value As String)
Dim threadList As List(Of Thread) = New List(Of Thread)

For i As Integer = 1 To 254
Dim t = New Thread(Sub() YTask(value))
t.IsBackground = True ' not sure why you want this if you are going to wait for the thread to finish anyways.
t.Start()
threadList.Add(t)
Next

' wait for all threads to finish.
' The loop will only exit once all threads have completed their work.
For Each t In threadList
t.Join()
Next

' Raise event now that all the threads have completed.
End Sub

EDIT: Making the number of threads adjustable

Usually, starting an excessive amount of threads to perform some work is not the best idea. Also depending on how resource intensive each of the thread's work is, it can cause an overall slowdown of your program.

Usually, you want to test which number of threads will give you the proper balance between accomplishing the work faster and in parallel vs. abusing system resources and causing overall performance degradation.

The following code should allow you to easily tune the number of threads to perform your work, and find the right balance for you.

Sub Main()
xTask("192.168.10.")
End Sub

Private Sub xTask(ByVal value As String)
Dim ipAddressesToScan As Queue(Of String) = New Queue(Of String)

SyncLock ipAddressesToScan ' I'm not 100% sure this locking is needed here, but I would do it to be safe, and it doesn't hurt.
For i As Integer = 1 To 254
ipAddressesToScan.Enqueue(value & i)
Next
End SyncLock

Dim threadList As List(Of Thread) = New List(Of Thread)
For i As Integer = 1 To 10 ' <-- change this to whatever number of threads seems to work best for you.
Dim t = New Thread(Sub() YTask(ipAddressesToScan))
't.IsBackground = True ' don't think you need this TBH.
t.Start()
threadList.Add(t)
Next

' Wait for all threads to finish processing the queue.
For Each t In threadList
t.Join()
Next

' Raise event HERE to signal that all the threads have completed.
Console.WriteLine("All threads have finished their work")
End Sub

Private Sub YTask(ByVal ipAddressesToScan As Queue(Of String))
Dim ipAddress As String
Do
SyncLock ipAddressesToScan
If ipAddressesToScan.Count = 0 Then
ipAddress = Nothing
Else
ipAddress = ipAddressesToScan.Dequeue
End If
End SyncLock

If Not String.IsNullOrEmpty(ipAddress) Then
' Perform your scan here...
Console.WriteLine(Thread.CurrentThread.ManagedThreadId & " is scanning IP Address " & ipAddress)
End If
Loop While Not String.IsNullOrEmpty(ipAddress)
End Sub


Related Topics



Leave a reply



Submit