How to print out all the threads and its current status? - java

Is there a way to print out all the threads and its id, status using code?
For example, I have 5 threads, and I want to enumerate all of them.

You can do as below.
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread thread: threadSet) {
System.out.println(thread.getId());
}
Make sure you read and understand the method Thread.getAllStackTraces() before using them.

Use
Thread.currentThread().getId();

Assign the thread object to a public variable if you need to control the thread from other parts of the program, or print it out directly if you just want to know what's running:
public int myThreadId = 0;
public void run () {
System.out.println("Thread Name: " + Thread.currentThread().getName(); // Printing the thread name
myThreadId = Thread.currentThread().getId(); // Assigning the thread ID to a public variable
}
Read more: How to Get a Reference to a Java Thread | eHow.com http://www.ehow.com/how_6879305_reference-java-thread.html#ixzz2FfEUe3cF
Also
Get a handle to the root ThreadGroup, like this:
ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( );
ThreadGroup parentGroup;
while ( ( parentGroup = rootGroup.getParent() ) != null ) {
rootGroup = parentGroup;
}
Now, call the enumerate() function on the root group repeatedly. The second argument lets you get all threads, recursively:
Thread[] threads = new Thread[ rootGroup.activeCount() ];
while ( rootGroup.enumerate( threads, true ) == threads.length ) {
threads = new Thread[ threads.length * 2 ];
}
Note how we call enumerate() repeatedly until the array is large enough to contain all entries.

Related

Only most recent task ExecutorService in Java

I want to create an ExecutorService in Java which, when given a task will stop and discard it's current task (if there is a current task) and execute the given task. When a new task is given to this ExecutorService it is always because the previous tasks became irrelevant an not worth executing anymore.
Is there a builtin way in Java to do this or should I resort to implementing this behavior myself? Or is there another approach which works better in this case?
This is an interesting problem. It took me a bit deeper into the core ExecutorService implementation. Thanks!
Solving without ExecutorService
From what you have mentioned, you will have atmost one thread executing tasks and atmost one task pending because we are interested only in the last submitted task. Do you really need an ExecutorService for this?
You can just hold the next task in a static AtomicReference field of a POJO object. Since we are interested only in the latest task, task producers may simply replace the object in the AtomicReference. The task consumer can get from this field as soon as the current task execution is done. The field must be:
static because there should be only one instance of this field
AtomicReference since multiple threads may be trying to set the next task.
Solving using ExecutorService
However, if you still want to go the ExecutorService way, you can try this out. Create a ThreadPoolExecutor with only one thread (core and maximum) and give it a BlockingQueue implementation that "forgets" all its elements as soon as a new one is added.
Here is a sample test code that submits new tasks 100 times. If the previous task has not been taken up for execution, it is discarded. If it has been, then it is executed and the new one is queued.
public class OnlyOneTask{
public static void main( String[] args ){
ExecutorService svc = null;
/* A BlockingQueue that immediately "forgets" all tasks it had as soon as a new one is "offered". */
BlockingQueue<Runnable> Q = new ArrayBlockingQueue<Runnable>( 1 ) {
private static final long serialVersionUID = 1L;
/* Forget the current task(s) and add the new one
* TODO These 2 steps may need synchronization. */
public boolean offer( Runnable e) {
clear();
return super.offer( e );
}
};
try {
/* A ThreadPoolExecutor that uses the queue we created above. */
svc = new ThreadPoolExecutor( 1, 1, 5000, TimeUnit.MILLISECONDS, Q );
for( int i = 0; i < 100; i++ ) {
/* Our simple task. */
int id = i;
Runnable r = () -> {
System.out.print( "|" + id + "|" );
};
svc.submit( r );
/* A delay generator. Otherwise, tasks will be cleared too fast. */
System.out.print( " " );
}
}
finally {
svc.shutdown();
try{
svc.awaitTermination( 10, TimeUnit.SECONDS );
}
catch( InterruptedException e ){
e.printStackTrace();
}
}
}
}
This sample class is only to give a sense of what I thought will work. You will certainly need to improve upon the following drawbacks in this implementation:
The first task is anyhow executed because it is immediately picked up by the ExecutorService. (This is why the next point becomes important.)
Interruptibility/cancellability has to be brought in to the running tasks, if necessary
Another way using ExecutorService and Future.cancel()
This is actually the simplest, if you are checking thread interruption in the task. This is basically the same as above but instead of clear()ing the queue, we simply use Future.cancel() to indicate that we don't need to execute the last task.
public static void main( String[] args ){
ExecutorService svc = null;
try {
/* A single thread executor is enough. */
svc = Executors.newSingleThreadExecutor();
Future<?> f = null;
for( int i = 0; i < 100; i++ ) {
int id = i;
/* Our simple task. */
Runnable r = () -> {
/* If the thread has been interrupted (by the Future.cancel() call, then return from here. */
if( Thread.currentThread().isInterrupted() ) return;
System.out.print( "|" + id + "|" );
};
if( f != null ) f.cancel( true );
f = svc.submit( r );
/* A pseudo delay generator. */
System.out.print( " " );
}
}
finally {
svc.shutdown();
try{
svc.awaitTermination( 10, TimeUnit.SECONDS );
}
catch( InterruptedException e ){
e.printStackTrace();
}
}
}

How to read all Thread Name, Running on JVM? [duplicate]

Is there any way I can get a list of all running threads in the current JVM (including the threads not started by my class)?
Is it also possible to get the Thread and Class objects of all threads in the list?
I want to be able to do this through code.
To get an iterable set:
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Performance: 0 ms for 12 threads (Azul JVM 16.0.1, Windows 10, Ryzen 5600X).
Get a handle to the root ThreadGroup, like this:
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentGroup;
while ((parentGroup = rootGroup.getParent()) != null) {
rootGroup = parentGroup;
}
Now, call the enumerate() function on the root group repeatedly. The second argument lets you get all threads, recursively:
Thread[] threads = new Thread[rootGroup.activeCount()];
while (rootGroup.enumerate(threads, true ) == threads.length) {
threads = new Thread[threads.length * 2];
}
Note how we call enumerate() repeatedly until the array is large enough to contain all entries.
Yes, take a look at getting a list of threads. Lots of examples on that page.
That's to do it programmatically. If you just want a list on Linux at least you can just use this command:
kill -3 processid
and the VM will do a thread dump to stdout.
You can get a lot of information about threads from the ThreadMXBean.
Call the static ManagementFactory.getThreadMXBean() method to get a reference to the MBean.
Have you taken a look at jconsole?
This will list all threads running for a particular Java process.
You can start jconsole from the JDK bin folder.
You can also get a full stack trace for all threads by hitting Ctrl+Break in Windows or by sending kill pid --QUIT in Linux.
You can try something like this:
Thread.getAllStackTraces().keySet().forEach((t) -> System.out.println(t.getName() + "\nIs Daemon " + t.isDaemon() + "\nIs Alive " + t.isAlive()));
and you can obviously get more thread characteristic if you need.
Apache Commons users can use ThreadUtils. The current implementation uses the walk the thread group approach previously outlined.
for (Thread t : ThreadUtils.getAllThreads()) {
System.out.println(t.getName() + ", " + t.isDaemon());
}
To get a list of threads and their full states using the terminal, you can use the command below:
jstack -l <PID>
Which <PID> is the id of process running on your computer. To get the process id of your java process you can simply run the jps command.
Also, you can analyze your thread dump that produced by jstack in TDAs (Thread Dump Analyzer) such fastthread or spotify thread analyzer tool.
In Groovy you can call private methods
// Get a snapshot of the list of all threads
Thread[] threads = Thread.getThreads()
In Java, you can invoke that method using reflection provided that security manager allows it.
Code snippet to get list of threads started by main thread:
import java.util.Set;
public class ThreadSet {
public static void main(String args[]) throws Exception{
Thread.currentThread().setName("ThreadSet");
for ( int i=0; i< 3; i++){
Thread t = new Thread(new MyThread());
t.setName("MyThread:"+i);
t.start();
}
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for ( Thread t : threadSet){
if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup()){
System.out.println("Thread :"+t+":"+"state:"+t.getState());
}
}
}
}
class MyThread implements Runnable{
public void run(){
try{
Thread.sleep(5000);
}catch(Exception err){
err.printStackTrace();
}
}
}
output:
Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE
If you need all threads including system threads, which have not been started by your program, remove below condition.
if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup())
Now output:
Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread :Thread[Reference Handler,10,system]:state:WAITING
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[ThreadSet,5,main]:state:RUNNABLE
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[Finalizer,8,system]:state:WAITING
Thread :Thread[Signal Dispatcher,9,system]:state:RUNNABLE
Thread :Thread[Attach Listener,5,system]:state:RUNNABLE
In the java console, hit Ctrl-Break. It will list all threads plus some information about the heap. This won't give you access to the objects of course. But it can be very helpful for debugging anyway.
public static void main(String[] args) {
// Walk up all the way to the root thread group
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parent;
while ((parent = rootGroup.getParent()) != null) {
rootGroup = parent;
}
listThreads(rootGroup, "");
}
// List all threads and recursively list all subgroup
public static void listThreads(ThreadGroup group, String indent) {
System.out.println(indent + "Group[" + group.getName() +
":" + group.getClass()+"]");
int nt = group.activeCount();
Thread[] threads = new Thread[nt*2 + 10]; //nt is not accurate
nt = group.enumerate(threads, false);
// List every thread in the group
for (int i=0; i<nt; i++) {
Thread t = threads[i];
System.out.println(indent + " Thread[" + t.getName()
+ ":" + t.getClass() + "]");
}
// Recursively list all subgroups
int ng = group.activeGroupCount();
ThreadGroup[] groups = new ThreadGroup[ng*2 + 10];
ng = group.enumerate(groups, false);
for (int i=0; i<ng; i++) {
listThreads(groups[i], indent + " ");
}
}
You can use getAllThreadIds that Returns all live thread IDs. Some threads included in the returned array may have been terminated when this method returns.
ManagementFactory.getThreadMXBean().getAllThreadIds()

Spawn multiple threads that take inputs from single collection and put results in single collection

Here is a brief of what i want to do , I have a scenario where
number of text files are generated dynamically on daily basis. 0
to 8 per day. size of each file can be small to big. depending on
day's data.
Need to run some checks (business checks) on them.
I plan to complete the task in minimum time, hence trying to write a parallel executor for performing checks on these files.
My idea is
Store n files in a concurrent collection (ConcurrentLinkedQueue)
remove a file, spawn a thread , that runs all checks on the file
since 1 file has no relation to another i want to be able to process multiple files
Store results in another concurrent collection ( ConcurrentLinkedQueue ... which is converted to different html pdf reports)
NOTE : number of threads can be different from number of files (I want to number of threads configurable , its not the case where number of file = number of threads )
My understanding is This way i should be able to complete the DAILY checks in minimum time.
I have my code like below , what confuses me "how to store all thread's results in single collection after each thread's completion" , my gut feeling is i am doing something funny (incorrect) the way i am storing results.
Second ques wanted to check if anyone forsees any other issues in code snippet below
Third ques this seems like a common use case ( to me ) any pointers to design pattern code snippets solving this
Note : i am using JDK 6.
public class CheckExecutor {
// to store all results of all threads here , then this will be converted to html/pdf files
static ConcurrentLinkedQueue<Result> fileWiseResult = new ConcurrentLinkedQueue<Result>();
public static void main(String[] args) {
int numberOfThreads=n; // need keep it configurable
Collection<ABCCheck> checksToExecute // will populate from business logic , ABCCheck is interface , has a method check() , there are different implementations
ConcurrentLinkedQueue<File> fileQueue = new ConcurrentLinkedQueue<File>(); // list of files for 1 day , may vary from 0 to 8
int maxNumOfFiles = fileQueue.size();
ThreadGroup tg = new ThreadGroup ("Group");
// If more number of threads than files (rare , can be considered corener case)
if (maxNumOfFiles < numberOfThreads) numberOfThreads=maxNumOfFiles;
// loop and start number of threads
for(int var=0;var<numberOfThreads;var++)
{
File currentFile = fileQueue.remove();
// execute all checks on 1 file using checksToExecute
ExecuteAllChecks checksToRun = new ExecuteAllChecks(); // business logic to populate checks
checksToRun.setchecksToExecute(checksToExecute);
checksToRun.setcheckResult(fileWiseResult); // when each check finishes want to store result here
new Thread (tg , checksToRun , "Threads for "+currentFile.getName()).start();
}
// To complete the tasak ... asap ... want to start a new thread as soon as any of current thread ends (diff files diff sizes)
while(!fileQueue.isEmpty()) {
try {
Thread.sleep(10000); // Not sure If this will cause main thread to sleep (i think it will pause current thread ) i want to pause main thread
} catch (InterruptedException e) {
e.printStackTrace();
}
// check processing of how many files completed
if( (tg.activeCount()<numberOfThreads) && (fileQueue.size()>0) ) {
int numOfThreadsToStart = numberOfThreads - tg.activeCount();
for(int var1=0;var1<numOfThreadsToStart;var1++) {
File currentFile = fileQueue.remove();
ExecuteAllchecks checksToRun = new ExecuteAllchecks();
checksToRun.setchecksToExecute(checksToExecute);
checksToRun.setcheckResult(fileWiseResult); // when each check finishes want to store result here
new Thread (tg , checksToRun , "Threads for "+currentFile.getName()).start();
}
}
}
}
}
class ExecuteAllchecks implements Runnable {
private Collection<ABCCheck> checksToExecute;
private ConcurrentLinkedQueue<Result> checkResult; // not sure if its correct , i want to store result off all threads here
public ConcurrentLinkedQueue<Result> getcheckResult() {
return checkResult;
}
// plan to instantiate the result collection globally and store result here
public void setcheckResult(ConcurrentLinkedQueue<Result> checkResult) {
this.checkResult = checkResult;
}
public Collection<ABCCheck> getchecksToExecute() {
return checksToExecute;
}
public void setchecksToExecute(Collection<ABCCheck> checksToExecute) {
this.checksToExecute = checksToExecute;
}
#Override
public void run() {
Result currentFileResult = new Result();
// TODO Auto-generated method stub
System.out.println("Execute All checks for 1 file");
// each check runs and calls setters on currentFileResult
checkResult.add(currentFileResult);
}
}
The actual implementation is very influenced by the nature of the computations itself, but somewhat general approach could be:
private final ExecutorService executor = Executors.newCachedThreadPool();
private final int taskCount = ...;
private void process() {
Collection< Callable< Result > > tasks = new ArrayList<>( taskCount );
for( int i = 0; i < taskCount; i++ ) {
tasks.add( new Callable< Result >() {
#Override
public Result call() throws Exception {
// TODO implement your logic and return result
...
return result;
}
} );
}
List< Future< Result > > futures = executor.invokeAll( tasks );
List< Result > results = new ArrayList<>( taskCount );
for( Future< Result > future : futures ) {
results.add( future.get() );
}
}
I would also recommend using sensible timeouts on future.get() invocations in order to executing thread not to stuck.
Still, I would't also recommend using cached thread pool in production as this pool is increasing whenever current pool doesn't have enough capacity for all tasks, but rather using something like Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() )
I you actual task could be splitter into several small ones and the later be joined consider checking how that could be efficiently be done using ForkJoin framework

How can I monitor life of threads?

I would like to know if there's a way to monitor the life of a thread but I'll explain the context of what I'm doing so maybe there's a better way to do this.
Basically I have x threads that are working on a queue and processing it, if a thread gets a acceptable result it goes into a solutions queue otherwise the data is either discarded or further processed.
My problem is in my main thread I have a like while(!solutions_results.isEmpty()) and it saves the data(right now its print to a file but later maybe database). The obvious problem is once it clears the solutions queue its done and finishes working even though the other threads are still putting data into the queue.
I'm not sure the best way to deal with this(maybe have a dedicated thread that only saves the solution queue?) but I was thinking if I could somehow monitor the life of the other threads are done then there's no chance of more data going into the solutions queue.
if there's a better way to do this please let me know otherwise is there a way to tell once the other threads are done(I can't wait for executor to completely finish before running this process because it can get quite large and don't want it to just sit in memory, ideally want to process it as it close to as it comes in but its not time dependent)?
If you use the ExecutorService to run your thread jobs then you can use the awaitTermination() method to know when all of the threads have finished:
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(yourSolutionsRunnable);
pool.submit(yourSolutionsRunnable);
...
// once you've submitted your last job you can do
pool.shutdown();
Then you can wait for all of the jobs submitted to finish:
pool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
This would get more complicated if your threads need to keep running after submitting their solutions. If you edit your question and make this more apparent I'll edit my answer.
Edit:
Oh, I see you want to process some results along the way but not stop until all of the threads are done.
You can use the pool.isTerminated() test which will tell you if all of the jobs have completed. So your loop would look something like:
// this is the main thread so waiting for solutions in a while(true) loop is ok
while (true) {
// are all the workers done?
if (pool.isTerminated()) {
// if there are results process one last time
if (!solutions_results.isEmpty()) {
processTheSolutions();
}
break;
} else {
if (solutions_results.isEmpty()) {
// wait a bit to not spin, you could also use a wait/notify here
Thread.sleep(1000);
} else {
processTheSolutions();
}
}
}
Edit:
You could also have two thread pools, one for generating the solutions and another one processing. Your main thread could then wait for the worker pool to empty and then wait for the solutions processing pool. The worker pool would submit the solutions (if any) into the solutions pool. You could just have 1 thread in the solutions processing pool or more as necessary.
ExecutorService workerPool = Executors.newFixedThreadPool(10);
final ExecutorService solutionsPool = Executors.newFixedThreadPool(1);
solutionsPool.submit(workerThatPutsSolutionsIntoSolutionsPool);
...
// once you've submitted your last worker you can do
workerPool.shutdown();
workerPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
// once the workers have finished you shutdown the solutions pool
solutionsPool.shutdown();
// and then wait for it to finish
solutionsPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
I don't know much about the behavior requirements that you're dealing with but if you want the main thread to block until all your child threads are complete you should take a look at the join method of the Thread class.
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()
Just run a loop inside your main thread that calls the join method on each one of your child threads and when it exits the loop you can be sure that all threads have finished working.
Just keep a list of your active threads. You'd want it synchronized to keep it from being trashed if you add/remove threads simultaneously. Or use something like java.util.concurrent.ConcurrentLinkedQueue, which can deal with multiple threads itself. Add each thread to the list when you start it. Each thread should remove itself from the list right before it stops. When the list is empty, all your threads are done.
Edit: the timing is important. First, the main thread has to put the working threads into the list. If they put themselves into the list, the main thread could check the list at a time when some threads have removed themselves from the list and all the rest, though started, have not yet begun executing--and so not yet put themselves in the list. It would then think everything was done when it wasn't. Second, the main thread must put each worker thread on the list before it starts it. Otherwise, the thread might finish and make its attempt to remove itself from the list before the main thread adds it to the list. Then the list will never become empty and the program will never finish.
Maybe java.util.concurrent.ExecutorCompletionService would be useful here.
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class monitor_life_of_threads
{
/**
* First, convert all of your threads to instances of Callable (easy to do), and have them each return an instance some class (I'm using Integer below just as
* an example).
* This will help simplify things.
*/
public static void main ( String args[] )
{
final monitor_life_of_threads worker = new monitor_life_of_threads();
worker.executeCallablesAndUseResults ();
System.exit ( 0 );
}
private void executeCallablesAndUseResults ()
{
List < Callable < Result >> list = new ArrayList <> ();
populateInputList ( list );
try
{
doWork ( list );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
catch ( ExecutionException e )
{
e.printStackTrace ();
}
catch ( CancellationException e )
{
/*
* Could be called if a Callable throws an InterruptedException, and if it's not caught, it can cause Future.get to hang.
*/
e.printStackTrace ();
}
catch ( Exception defaultException )
{
defaultException.printStackTrace ();
}
}
private void doWork ( Collection < Callable < Result >> callables ) throws InterruptedException, ExecutionException
{
ExecutorService executorService = Executors.newCachedThreadPool ();
CompletionService < Result > ecs = new ExecutorCompletionService < > ( executorService );
for ( Callable < Result > callable : callables )
ecs.submit ( callable );
for ( int i = 0, n = callables.size (); i < n; ++i )
{
Result r = ecs.take ().get ();
if ( r != null )
use ( r ); // This way you don't need a second queue.
}
executorService.shutdown ();
}
private void use ( Result result )
{
// Write result to database, output file, etc.
System.out.println ( "result = " + result );
}
private List < Callable < Result >> populateInputList ( List < Callable < Result >> list )
{
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, then return a 5.
return new Result ( 5 );
}
} );
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, then return an 8.
return new Result ( 8 );
}
} );
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, but fail and so return null.
return null;
}
} );
return list;
}
}
class Result
{
private Integer i;
Result ( Integer i)
{
this.i = i;
}
public String toString ()
{
return Integer.toString ( i );
}
}

How can I make sure a threadpool is finished?

The setup:
I am in the process of changing the way a program works under the hood. In the current version works like this:
public void threadWork( List<MyCallable> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
List<Future<myOutput>> returnValues = new ArrayList<Future<myOutput>>();
List<myOutput> finishedStuff = new ArrayList<myOutput>();
for( int i = 0; i < workQueue.size(); i++ )
{
returnValues.add( pool.submit( workQueue.get(i) ) );
}
while( !returnValues.isEmpty() )
{
try
{
// Future.get() waits for a value from the callable
finishedStuff.add( returnValues.remove(0).get(0) );
}
catch(Throwable iknowthisisbaditisjustanexample){}
}
doLotsOfThings(finsihedStuff);
}
But the new system is going to use a private inner Runnable to call a synchronized method that writes the data into a global variable. My basic setup is:
public void threadReports( List<String> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
List<MyRunnable> runnables = new ArrayList<MyRunnable>()
for ( int i = 0; i < modules.size(); i++ )
{
runnables.add( new MyRunnable( workQueue.get(i) );
pool.submit(threads.get(i));
}
while( !runnables.isEmpty() )
{
try
{
runnables.remove(0).wait(); // I realized that this wouldn't work
}
catch(Throwable iknowthisisbaditisjustanexample){}
}
doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}
If you read my comment in the try of the second piece of code you will notice that I don't know how to use wait(). I had thought it was basically like thread.join() but after reading the documentation I see it is not.
I'm okay with changing some structure as needed, but the basic system of taking work, using runnables, having the runnables write to a global variable, and using a threadpool are requirements.
The Question
How can I wait for the threadpool to be completely finished before I doLotsOfThings()?
You should call ExecutorService.shutdown() and then ExecutorService.awaitTermination.
...
pool.shutdown();
if (pool.awaitTermination(<long>,<TimeUnit>)) {
// finished before timeout
doLotsOfThings(finsihedStuff);
} else {
// Timeout occured.
}
Try this:
pool.shutdown();
pool.awaitTermination(WHATEVER_TIMEOUT, TimeUnit.SECONDS);
Have you considered using the Fork/Join framework that is now included in Java 7. If you do not want to use Java 7 yet you can get the jar for it here.
public void threadReports( List<String> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
Set<Future<?>> futures = new HashSet<Future<?>>();
for ( int i = 0; i < modules.size(); i++ )
{
futures.add(pool.submit(threads.get(i)));
}
while( !futures.isEmpty() )
{
Set<Future<?>> removed = new Set<Future<?>>();
for(Future<?> f : futures) {
f.get(100, TimeUnit.MILLISECONDS);
if(f.isDone()) removed.add(f);
}
for(Future<?> f : removed) futures.remove(f);
}
doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}
shutdownis a lifecycle method of the ExecutorService and renders the executor unusable after the call. Creating and destroying ThreadPools in a method is as bad as creating/destroying threads: it pretty much defeats the purpose of using threadpool, which is to reduce the overhead of thread creation by enabling transparent reuse.
If possible, you should maintain your ExecutorService lifecycle in sync with your application. - create when first needed, shutdown when your app is closing down.
To achieve your goal of executing a bunch of tasks and waiting for them, the ExecutorService provides the method invokeAll(Collection<? extends Callable<T>> tasks) (and the version with timeout if you want to wait a specific period of time.)
Using this method and some of the points mentioned above, the code in question becomes:
public void threadReports( List<String> workQueue ) {
List<MyRunnable> runnables = new ArrayList<MyRunnable>(workQueue.size());
for (String work:workQueue) {
runnables.add(new MyRunnable(work));
}
// Executor is obtained from some applicationContext that takes care of lifecycle mgnt
// invokeAll(...) will block and return when all callables are executed
List<Future<MyRunnable>> results = applicationContext.getExecutor().invokeAll(runnables);
// I wouldn't use a global variable unless you have a VERY GOOD reason for that.
// b/c all the threads of the pool doing work will be contending for the lock on that variable.
// doLotsOfThings(finishedStuff);
// Note that the List of Futures holds the individual results of each execution.
// That said, the preferred way to harvest your results would be:
doLotsOfThings(results);
}
PS: Not sure why threadReports is void. It could/should return the calculation of doLotsOfThings to achieve a more functional design.

Categories