I had been making a game, and was using Threads in my program to carry out tasks. So let me explain the scenario a bit. I have a BattleManager class which implements Runnable and keep looping in the battle queue for battles, if there are any.
#Override
public void run() {
while(serverRunning){
synchronized (battleQueue) {
for(Battle battle : battleQueue){
if(battle != null){
if (battle instanceof WildBattle) {
if(!((WildBattle) battle).isBattleOver()){
((WildBattle) battle).tryExecuteBattleTurn();
}else{
battleQueue.remove(battle);
battle = null;
}
}
}
}
}
try {
Thread.sleep(3);
} catch (InterruptedException e)
e.printStackTrace();
}
}
currentThread = null;
}
Then I check if battle is not over, and if not I try to execute the battle turn. Since there can be more than 100 battles running at the same time and there are complex calculations inside every battle, I inside WildBattle class spawn a child thread to execute the task, so that the battles run in parallel.
Here is the method which is invoked inside wild battle class, which spawns a new thread.
public void tryExecuteBattleTurn() {
if (!isBattleTurnRunning && battleThread == null) {
battleThread = new Thread(new Runnable() {
#Override
public void run() {
//long startTime = System.currentTimeMillis();
executeBattle();
battleLog.setBattleLog("");
battleThread = null;
//System.err.println("Total execution time : " +(System.currentTimeMillis() - startTime));
}
}, "Battle thread");
battleThread.start();
}
}
Now the main question is, I want to learn about executor service and I read at few places that it is always better to use executor service rather than spawning new child threads. How can I change this to use executor service.
I am not sure though. I am not a java expert and still learning the language so spare me if you see something is wrong, and please let me know if I can change anything to make it more efficient.
Let me know if you are not clear about anything.
I'll show you a basic example and you'll manage how to integrate it with your code
First you create ExecutorService somewhere in your application.
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
You should choose NUMBER_OF_THREADS based on your application needs. Threads are not created immediately - only when you submit a task to service and there are no available threads for it. If all NUMBER_OF_THREADS are busy, task will wait in queue until one of the threads will be able to handle it. ExecutorService will reuse threads, this will save time on thread instantiation and is a generally good concept to work with threads.
Then you manage how to access executor service from your battles. Then, when you need to perform an asynchronous work you submit task to service:
executorService.submit(new Runnable() {
#Override public void run() {
// your code here
}
}
If your application has a lifecycle and can be somehow shutdown, you'd like to shutdown ExecutorService as well. There are two options - shutdown() and shutdownNow(), first one waits for all current tasks to be executed, second one performs shutdown immediately and returns list of tasks that were not completed.
As was mentioned in comments, you should figure out how to preserve model state and organize thread synchronization based on your real situation.
Related
I have a BlockingQueue of Runnable - I can simply execute all tasks using one of TaskExecutor implementations, and all will be run in parallel.
However some Runnable depends on others, it means they need to wait when Runnable finish, then they can be executed.
Rule is quite simple: every Runnable has a code. Two Runnable with the same code cannot be run simultanously, but if the code differ they should be run in parallel.
In other words all running Runnable need to have different code, all "duplicates" should wait.
The problem is that there's no event/method/whatsoever when thread ends.
I can built such notification into every Runnable, but I don't like this approach, because it will be done just before thread ends, not after it's ended
java.util.concurrent.ThreadPoolExecutor has method afterExecute, but it needs to be implemented - Spring use only default implementation, and this method is ignored.
Even if I do that, it's getting complicated, because I need to track two additional collections: with Runnables already executing (no implementation gives access to this information) and with those postponed because they have duplicated code.
I like the BlockingQueue approach because there's no polling, thread simply activate when something new is in the queue. But maybe there's a better approach to manage such dependencies between Runnables, so I should give up with BlockingQueue and use different strategy?
If the number of different codes is not that large, the approach with a separate single thread executor for each possible code, offered by BarrySW19, is fine.
If the whole number of threads become unacceptable, then, instead of single thread executor, we can use an actor (from Akka or another similar library):
public class WorkerActor extends UntypedActor {
public void onReceive(Object message) {
if (message instanceof Runnable) {
Runnable work = (Runnable) message;
work.run();
} else {
// report an error
}
}
}
As in the original solution, ActorRefs for WorkerActors are collected in a HashMap. When an ActorRef workerActorRef corresponding to the given code is obtained (retrieved or created), the Runnable job is submitted to execution with workerActorRef.tell(job).
If you don't want to have a dependency to the actor library, you can program WorkerActor from scratch:
public class WorkerActor implements Runnable, Executor {
Executor executor=ForkJoinPool.commonPool(); // or can by assigned in constructor
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueu<>();
boolean running = false;
public synchronized void execute(Runnable job) {
queue.put(job);
if (!running) {
executor.execute(this); // execute this worker, not job!
running=true;
}
public void run() {
for (;;) {
Runnable work=null;
synchronized (this) {
work = queue.poll();
if (work==null) {
running = false;
return;
}
}
work.run();
}
}
}
When a WorkerActor worker corresponding to the given code is obtained (retrieved or created), the Runnable job is submitted to execution with worker.execute(job).
One alternate strategy which springs to mind is to have a separate single thread executor for each possible code. Then, when you want to submit a new Runnable you simply lookup the correct executor to use for its code and submit the job.
This may, or may not be a good solution depending on how many different codes you have. The main thing to consider would be that the number of concurrent threads running could be as high as the number of different codes you have. If you have many different codes this could be a problem.
Of course, you could use a Semaphore to restrict the number of concurrently running jobs; you would still create one thread per code, but only a limited number could actually execute at the same time. For example, this would serialise jobs by code, allowing up to three different codes to run concurrently:
public class MultiPoolExecutor {
private final Semaphore semaphore = new Semaphore(3);
private final ConcurrentMap<String, ExecutorService> serviceMap
= new ConcurrentHashMap<>();
public void submit(String code, Runnable job) {
ExecutorService executorService = serviceMap.computeIfAbsent(
code, (k) -> Executors.newSingleThreadExecutor());
executorService.submit(() -> {
semaphore.acquireUninterruptibly();
try {
job.run();
} finally {
semaphore.release();
}
});
}
}
Another approach would be to modify the Runnable to release a lock and check for jobs which could be run upon completion (so avoiding polling) - something like this example, which keeps all the jobs in a list until they can be submitted. The boolean latch ensures only one job for each code has been submitted to the thread pool at any one time. Whenever a new job arrives or a running one completes the code checks again for new jobs which can be submitted (the CodedRunnable is simply an extension of Runnable which has a code property).
public class SubmissionService {
private final ExecutorService executorService = Executors.newFixedThreadPool(5);
private final ConcurrentMap<String, AtomicBoolean> locks = new ConcurrentHashMap<>();
private final List<CodedRunnable> jobs = new ArrayList<>();
public void submit(CodedRunnable codedRunnable) {
synchronized (jobs) {
jobs.add(codedRunnable);
}
submitWaitingJobs();
}
private void submitWaitingJobs() {
synchronized (jobs) {
for(Iterator<CodedRunnable> iter = jobs.iterator(); iter.hasNext(); ) {
CodedRunnable nextJob = iter.next();
AtomicBoolean latch = locks.computeIfAbsent(
nextJob.getCode(), (k) -> new AtomicBoolean(false));
if(latch.compareAndSet(false, true)) {
iter.remove();
executorService.submit(() -> {
try {
nextJob.run();
} finally {
latch.set(false);
submitWaitingJobs();
}
});
}
}
}
}
}
The downside of this approach is that the code needs to scan through the entire list of waiting jobs after each task completes. Of course, you could make this more efficient - a completing task would actually only need to check for other jobs with the same code, so the jobs could be stored in a Map<String, List<Runnable>> structure instead to allow for faster processing.
I want to create a health checker, which will check the health of a java process. My process does a lot of things and is multi threaded. Various exceptions could be thrown, like Service / SQL / IO, etc. My plan is to call the HealthChecker to check for the process, from the catch block, in the individual threads. This will check for all the different healths, and in the case where there is any issue it will pause the threads, and log appropriately. There will be other processes which will read the logs by the process, and alert support to take appropriate actions.
Below is the general structure of the java process.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Schedular {
private static int numOfTasks = 10 ;
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
while(true){
for(int i=0;i<numOfTasks;i++){
service.execute(new Workers());
}
}
}
}
class Workers implements Runnable{
#Override
public void run() {
/*
* This can throw different exceptions , eg:
*/
try{
}catch(Exception e){
e.printStackTrace();
HealthChecker.checkHealth();
}
}
}
class HealthChecker{
public static void checkHealth() {
//Check health and then , log and pause all the threads
}
}
I am not able to figure out a way to pause all the threads. If there is a db exception I want all the threads to pause. I am requesting some suggestions.
You need a way to block the threads until some event occurs that allows the threads to continue. I see some major issues with the code:
1) The while(true) in your main thread might lead to a StackOverflowError. With each iteration of the while loop, you will add 10 more threads to the executor, and this will just continue unbounded.
2) There is no loop in your run() so that even if an exception is caught and we wait for the HealthCheck, the run() method would still exit. While a loop is not needed in your run() if you can constantly execute new Threads from your main thread to take the place of the terminated one, but that logic is not presently there in the main loop.
But setting those concerns aside here is one way to block worker threads until some event (presumably a HealthCheck all clear) occurs.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Schedular {
private static int numOfTasks = 10 ;
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
HealtchChecker hChecker = new HealthChecker();
for(int i=0;i<numOfTasks;i++){
service.execute(new Workers(hChecker));
}
}
}
class Workers implements Runnable{
private HealtchChecker hChecker;
public Workers(HealtchChecker hChecker){
this.hChecker = hChecker;
}
#Override
public void run() {
/*
* This can throw different exceptions , eg:
*/
while(true) {
try{
}catch (InterruptedException ie) {
throw ie;
}catch(Exception e){
e.printStackTrace();
HealthChecker.checkHealth();
}
}
}
}
class HealthChecker implements Runnable {
private final Semaphore semaphore = new Semaphore(1, true);
public void checkHealth() {
try {
semaphore.acquire();
} finally {
semaphore.release();
}
}
#Override
public void run(){
//code to check for errors that cause threads to pause.
if (inErrorState) {
semaphore.acquire();
} else {
semaphore.release();
}
}
}
A few things worth mentioning.
1) The main thread only creates 10 threads, versus an unbounded amount. You can adjust this as needed.
2) The Worker thread is long lived, meaning it will continue running even if it encounters Exceptions, except for an InterruptException.
3) HealthCheck is no longer a static object. it is instead a shared object.
4) HealthCheck is a runnable that can be executed in its own thread for monitoring for errors. I did not add the code to execute this thread.
5) HealCheck uses a Semaphore to cause the threads to block until the error state is cleared. I looked for other objects that can do this, like CountDownLatch or CyclicBarrier or Phaser, but this one came closest to giving us what we need to block all the threads from one point (the run() method).
Its not perfect but I think it gets you a little bit closer to what you want.
You're venturing pretty far afield from best practices, but you didn't ask about best practices for monitoring the health of threads - so I won't answer that question. Instead, I'll just answer the question you asked: how can I pause a set of threads managed by an ExecutorService?
Assuming that your Workers.run() will eventually end without intervention (in other words, it's not in an infinite loop - intentional or otherwise), the right thing to do is to call service.shutdown() (where service is your instance of ExecutorService). To do this, you can pass service in to HealthCheck.healthCheck() as a new parameter. Calling shutdown() will allow the currently-running threads to complete, then stop the executor.
If Workers.run() will not naturally complete, best practice says that you need to change your code such that it will. There is a Thread.stop() method you can call to halt the thread and a Thread.suspend() method you can call to suspend the thread. Both of these are double-bad ideas for you to use for two reasons:
They are Deprecated and will leave the Threads in a super-unhealthy state. You will have very difficult problems in the future if you use them.
You are using ExecutorService. That means you are delegating thread management to that class. If you go messing with the state of the Threads underneath ExecutorService, it can't manage the thread pool for you and, again, you will have very difficult problems in the future.
I have a MainClass, a Worker class and a Supervisor class. In MainClass i create 10 Worker classes and a Supervisor class that run in separate threads.
class MainClass {
public static void main(String args[]) {
for (int i=0; i<10 ;i++) {
Thread t = new Thread( new Worker());
t.start();
}
(new Thread(new Supervisor()).start();
}
.
class Worker extends Thread {
public void run() {
while(true) {
if(some_condition) {
//do stuff
} else {
// pause thread execution for undefined time.
}
}
}
}
.
class Supervisor extends Thread {
public void run() {
while(true) {
if(some_condition) {
// restart Workers thread that are paused.
}
// do other stuff
}
}
}
I don't know how to implement this, cause the conditions in every thread are independent from each other so i don't need to synchronize, so i can't use wait-notify.
I don't know how to implement this, cause the conditions in every thread are independent from each other so i don't need to synchronize, so i can't use wait-notify.
Sure you can.
The subtlety here is that presumably Supervisor doesn't actually know whether worker threads are really paused. (If it does, then the conditions are not independent.)
Since Supervisor doesn't know whether the threads are actually paused (by assumption), you have to design what you want to happen if it tries to unpause an already-unpaused thread.
a) Should an unpause do nothing?
b) Or should it immediately unpause the next time a worker tries to pause itself?
If the answer is (b), then you have to worry about thread safety. If the answer is (a), then you don't (unless you have some other data to pass between threads!)
Either way, you can still use wait and notify.
As per my understanding u want to create separate thread pools which consist of 10 workers or number as per your requirement.
As far as pools are concerned you can check for ThreadPoolExecutor in java.util.concurrent api. Internally ThreadPoolexecutor also creates worker Threads for running tasks.
Try reading ThreadPoolExecutor it might help you or please elaborate your question whats your ultimate objective you wish to achieve by this problem.
Is there a way to use ExecutorService to pause/resume a specific thread?
private static ExecutorService threadpool = Executors.newFixedThreadPool(5);
Imagine that I want to stop the thread which as the id=0 (assuming that to each one is assigned an incremental id until the size of the threadpool is reached).
After a while, by pressing a button let's say, I want to resume that specific thread and leave all the other threads with their current status, which can be paused or resumed.
I have found on Java documentation a uncompleted version of PausableThreadPoolExecutor. But it doesn't suit what I need because it resume all the threads in the pool.
If there's no way to do it with the default implementation of the ExecutorService can anyone point me to a Java implementation for this problem?
You are on the wrong track. The thread pool owns the threads and by sharing them with your code could mess things up.
You should focus on making your tasks (passed to the threads cancellable/interruptable) and not interact with the threads owned by the pool directly.
Additionally you would not know what job is being executed at the time you try to interrupt the thread, so I can't see why you would be interested in doing this
Update:
The proper way to cancel your task submitted in the thread pool is via the Future for the task returned by the executor.
1)This way you know for sure that the task you actually aim at is attempted to be cancelled
2)If your tasks are already designed to be cancellable then your are half way there
3) Do not use a flag to indicate cancellation but use Thread.currentThread().interrupt() instead
Update:
public class InterruptableTasks {
private static class InterruptableTask implements Runnable{
Object o = new Object();
private volatile boolean suspended = false;
public void suspend(){
suspended = true;
}
public void resume(){
suspended = false;
synchronized (o) {
o.notifyAll();
}
}
#Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
if(!suspended){
//Do work here
}
else{
//Has been suspended
try {
while(suspended){
synchronized(o){
o.wait();
}
}
}
catch (InterruptedException e) {
}
}
}
System.out.println("Cancelled");
}
}
/**
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
ExecutorService threadPool = Executors.newCachedThreadPool();
InterruptableTask task = new InterruptableTask();
Map<Integer, InterruptableTask> tasks = new HashMap<Integer, InterruptableTask>();
tasks.put(1, task);
//add the tasks and their ids
Future<?> f = threadPool.submit(task);
TimeUnit.SECONDS.sleep(2);
InterruptableTask theTask = tasks.get(1);//get task by id
theTask.suspend();
TimeUnit.SECONDS.sleep(2);
theTask.resume();
TimeUnit.SECONDS.sleep(4);
threadPool.shutdownNow();
}
Suggestion: Similarly to/instead of the flags you're using, create a semaphore with 1 permit (new Semaphore(1)) for each task you need to pause/unpause. At the beginning of the task's working cycle put a code like this:
semaphore.acquire();
semaphore.release();
This causes the task to acquire a semaphore permit and immediately release it. Now if you want to pause the thread (a button is pressed, for example), call semaphore.acquire() from another thread. Since the semaphore has 0 permits now, your working thread will pause at the beginning of the next cycle and wait until you call semaphore.release() from the other thread.
(The acquire() method throws InterruptedException, if your working thread gets interrupted while waiting. There is another method acquireUninterruptibly(), which also tries to acquire a permit, but doesn't get interrupted.)
One scenario could be, one wants to simulate a number of devices. Devices have functions. Altogether this collection of devices runs concurrently. And now if a thread represents a device ( or one thread for one function of a device ), one might want to control the life cycle of the device like start(), shutdown(), resume()
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?
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.
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.
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.
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?
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.
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.
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.
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.
I guess the easiest way is to use ThreadPoolExecutor class.
It has a queue and you can set how many threads should be working in parallel.
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
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();
}
}
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!
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();
}
You could also use SwingWorker, which has built-in property change support. See addPropertyChangeListener() or the get() method for a state change listener example.
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.