How to know if other threads have finished?
There are a number of ways you can do this:
- Use Thread.join() in your main thread to wait in a blocking fashion for each Thread to complete, or
- Check Thread.isAlive() in a polling fashion -- generally discouraged -- to wait until each Thread has completed, or
- 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
- Use locks or synchronizers or mechanisms from java.util.concurrent, or
- 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
How to Find Files That Match a Wildcard String in Java
"Program to an Interface". What Does It Mean
How to Check If the User Is Pressing a Key
Auto Errors Detection in Intellij Idea
Why Doesn't Java Send the Client Certificate During Ssl Handshake
Regex for Matching Something If It Is Not Preceded by Something Else
Java String Split with "." (Dot)
Where Are Static Methods and Static Variables Stored in Java
Handling Parenthesis While Converting Infix Expressions to Postfix Expressions
Unrecognized Ssl Message, Plaintext Connection? Exception
Number of Days Between Two Dates in Joda-Time
How to Set the Default Locale in the Jvm
Java.Lang.Classnotfoundexception: Com.Mysql.Jdbc.Driver in Eclipse
Java and Gui - Where Do Actionlisteners Belong According to MVC Pattern
How to Increase the Jvm Memory