I have a series of different "tasks" to be done using the same thread pool. I want to measure the time it takes to perform each task, but for that I need to wait for every task in the "task" (sorry for ambiguity) to finish.
When there's just one task I would normally do this:
ExecutorService e = Executors.newCachedThreadPool();
for (int i=0; i<100; ++i)
e.submit(target);
e.shutdown();
while (!e.isTerminated());
But since there will be several task submitted to the pool, I can't it down. All the methods that have something to do with waiting for the tasks to finish mention "after shutdown request". Well, what if I don't want to shut it down, but wait for all the threads to finish and then submit more tasks?
This is what I want to do:
ExecutorService e = Executors.newCachedThreadPool();
for (int i=0; i<100; ++i)
e.submit(target);
// wait for all targets to finish
for (int i=0; i<100; ++i)
e.submit(target); // submit different tasks
// wait... and so on
I thought of shutting the pool down and then "waking it up" again using prestartAllCoreThreads, but then I realized this was not an ExecutorService method but a ThreadPoolExecutor method. Could this be a solution? Shutting it down, waiting, and then activating the pool again? Seems a bit ugly to me.
I also thought that the most natural thing to do was to use a CyclicBarrier, but it seems too a specific way of doing this, while I think it would be the most logical thing to be able to use any ExecutorService for what I'm trying to do.
Is there any way I could stick to ExecutorServices and wait for all the tasks to finish?
Use CyclicBarrier for the work you need like so :
// the optionalRunnable can collect the data gathered by the tasks
CyclicBarrier b = new CyclicBarrier(numberOfTasks,optionalRunnable)
Task yourTaks = new Task(...., b);
// inside the run method call b.await() after the work is done;
executor.submit(yourTaks);
Optionally , you can also call await in the main thread and instantiate the barrier to numTasks + 1 . That way you are sure you're resubmitting tasks to the executor only after it's done processing the current batch
You can await the termination of that ExecutorService.
ExecutorService executor = Executors.newCachedThreadPool();
//do your stuff
try {
executor.shutdown();
executor.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
//handle
}
Or use a CountDownLatch:
CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
try {
latch.await();
} catch (InterruptedException E) {
// handle
}
and within your task (enclose in try / finally)
latch.countDown();
You could create a TaskListener interface which you pass into each task. Each task notifies the TaskListener when they start and stop. Then you can create a TimingTaskListener implementation which maintains a ConcurrentMap of the durations which can be queried later.
public interface TaskListener {
void onStart(String taskId);
void onEnd(String taskId);
}
public class Task implements Runnable {
private TaskListener taskListener;
private String taskId;
public Task(String taskId, TaskListener taskListener) {
this.taskId = taskId;
this.listener = listener;
}
public void run() {
listner.onStart(taskId);
try {
doStuff();
} finally {
listener.onEnd(taskId);
}
}
}
// TODO: Implement TimingTaskListener to save durations to a ConcurrentMap
TimingTaskListener timingListener = new TimingTaskListener();
Runnable task1 = new Task("task1", timingListener);
Runnable task2 = new Task("task2", timingListener);
Future<?> f1 = e.submit(task1);
Future<?> f2 = e.submit(task2);
// futures block until the task is finished.
// You could also use a CountDownLatch to achieve the same
f1.get();
f2.get();
long time1 = timingListener.getDuration("task1");
long time2 = timingListener.getDuration("task2");
Related
I am creating a thread pool executor and want it to finish all tasks before going forward:
for Example:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
taskExecutor.execute(new MyTask());
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
there are multiple ways to do so:
but the popular one is using threadpool.shutdown():
public void awaitTerminationAfterShutdown(ExecutorService threadPool) {
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
threadPool.shutdownNow();
}
} catch (InterruptedException ex) {
threadPool.shutdownNow();
Thread.currentThread().interrupt();
}
}
Different from the answer written, in scenarios the person will not usually know when the job finishes. As a rule of thumb, a more better approach is to have a callback from the running task.
You can do so like the following:
class MyTask implements Callable {...}//and do your task inside the "call" method
And then :
List<MyTask> allMyTasks // have all your tasks piled up
List<Future<TaskOutPut>> futures = taskExecutor.invokeAll(allMyTasks);
List<TaskOutPut> output = futures.map(future->future.get()).collect(Collectors.toList()); //this will make sure every future is completed
I have a Servlet which recieves a request, has to process 5 tasks (Grab data Form external Servers) and send all the data back to the client ordered.
How to process the 5 Task simultaneously and continue with the servlet code after all 5 tasks are completed?
You can use CoundDownLatch
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
sample code:
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(5); // 5 tasks
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final int threadNumber;
// you can pass additional arguments as well
Worker(CountDownLatch startSignal, CountDownLatch doneSignal,
int threadNumber) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.threadNumber = threadNumber;
}
public void run() {
try {
startSignal.await();
doWork(); // actual work to be performed here
doneSignal.countDown();
} catch (InterruptedException ex) {
LOGGER.error(ex);
}
}
}
// 5 new threads are started
for(int i=1;i<=5;i++){
new Thread(new Worker(startSignal, doneSignal, i)).start();
}
startSignal.countDown(); // let all threads proceed
try {
doneSignal.await(); // wait for all to finish
// all 5 tasks are finished and do whatever you want to do next
} catch (InterruptedException interruptedException) {
LOGGER.error(interruptedException);
}
Read more... and Find more examples...
Another option is the ExecutorService. There are a variety of examples available including the following:
How to wait for all threads to finish, using ExecutorService?
ExecutorService, how to wait for all tasks to finish
Here is some example code taken from the first link found above:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
...
}
5 seconds is too long, it might take up the web server resource, you can let the client to send a request A, which trigger your 5 seconds task, but it don't wait, return immediately.Since you know it will take 5 seconds, you can send another request B, 5 seconds later, to get the data. If data not ready yet, you can request after another 5 seconds, until MAX_RETRY_COUNT (defined by yourself) reached.
I have the following code hashed out:
public class MyCallable implements Callable<Long> {
#Override
public Long call() throws Exception {
// Do stuff...
}
}
public class MyController {
private ExecutorService executor = Executos.newCachedTreadPool();
public Long concurrentDoStuff() {
List<MyCallable> workers = makeWorkers();
List<Long> allResults = new ArrayList<Long>();
for(MyCallable worker : workers) {
Future<Long> workerResults = executor.submit(worker);
try {
allResults.add(workerResults.get());
} catch(InterruptedException ie) {
// Handle...
} catch(ExecutionException ee) {
// Handle...
}
}
// Question: how do I pause here and wait for all workers to finish?
}
}
After the for-loop, I want to wait for all workers to finish before proceeding any further. What's the best/safest/most-efficient way to do this? Thanks in advance!
Use a CountDownLatch.
Initialize it with the number of workers
Pass a reference to the latch in the worker constructor
When the worker is done, call countDown
Call await in the main thread and it will block until the workers are done.
This is a more general-purpose solution than using methods on the executor service.
You must shut the Executor down with shutDown and then wait until all jobs have been processed with awaitTermination.
You can call:
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE , TimeUnit.NANOSECONDS);
This will wait (almost) indefinitely for the tasks to complete.
There is a handy method.
ExecutorService.invokeAll(List<Callable> callables);
It will return List<Future> objects so that you can get the returned objects of all your individual call() methods.
You can get the instance of ExecutorService by calling Executors.new....()
Consider following code:
SwingWorker<Void, Void> sworker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
try {
for (int j = 0; j < 5; j++) {
Callable<Object> worker = new MyCallableImpl();
Future<Object> future = executor.submit(worker);
array[j] = future.get();
}
} catch (InterruptedException e) {
// some code here
} catch (ExecutionException e) {
// some code here
}
// some code here
executor.shutdown();
return null;
}
};
sworker.execute();
As I said in the title: is this a good practice to invoke ExecutorService inside doInBackground() method of SwingWorker? It works for me (JDK1.7), GUI is not blocked and multiple threads from Executor pool are running in background, but still I have some doubts...
The above code doesn't make much sense to me.
If the objective here is to ensure that the GUI remains responsive while a long-running task is being executed, then there's no need to use the ExecutorService since the SwingWorker already provides that mechanism.
can executing SwingWorkers instance from Executor
have to accepting that Executor doesn't care about SwingWorkers lifecycle and vice versa
have to implement PropertyChangeListener for SwingWorker
exmple here
To further mre's response. It doesn't make sense because your execution is actually single-threaded. The doInBackground will submit to the executor and wait for that single task to complete then submit another.
You should submit the same way, but store the returned Futures in a List of some sort then get on each one of them after all tasks have been submitted.
I don't as much mind the doInBackground to submit these jobs asynchronously as mre does. If you are trying to submit a number of tasks and have only N submitted at any given time you definitely shouldn't do this through SwingWorker.doInBackground. Using an ExectorService + SwingUtilities.invokeLater I think is the better way.
And just to clarify any confusion, invokeLater should only be used here when the task within the ExecutorService is complete and all it needs to do is update the UI component.
Edit: Example to address your comment
protected Void doInBackground() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Future> futures = ...;
try {
for (int j = 0; j < 5; j++) {
Callable<Object> worker = new MyCallableImpl();
futures.add(executor.submit(new Callable<Object>(){
public Object call(){
//expensive time consuming operation
final String result = ...;//result from consuming operation
SwingUtilities.invokeLater(new Runnable(){
public void run(){
jLabel.setText(result);
}
});
return new Object();
}
));
}
for(Future<Object> f :futures)f.get();
executor.shutdown();
return null;
}
Notice how the invokeLater is done to do a simple update? That should not cause your EDT to freeze.
I'm writing a swing application with HttpClient and I need a way to make a download list because I need to wait 1 minute (for example) before starting a new download.
So I would like to create a waiting list of threads (downloads).
I would have a class that takes a time parameter and contains a list of threads and when I add a thread in the list it starts if there is no running thread. Otherwise it waits for its turn.
Is there any tool to do that ?
Thanks a lot for your help.
Yes. ScheduledExecutorService. You can create a fixed length service via Executors.newScheduledThreadPool(corePoolSize). When you are ready to submit the task to wait the amount of time just submit it to ScheduledExecutorService.schedule
ScheduledExecutorService e = Executors.newScheduledThreadPool(10)
private final long defaultWaitTimeInMinutes = 1;
public void submitTaskToWait(Runnable r){
e.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
}
Here the task will launch in 1 minute from the time of being submitted. And to address your last point. If there are currently tasks being downloaded (this configuration means 10 tasks being downloaded) after the 1 minute is up the runnable submitted will have to wait until one of the other downloads are complete.
Keep in mind this deviates a bit from the way you are designing it. For each new task you wouldnt create a new thread, rather you would submit to a service that already has thread(s) waiting. For instance, if you only want one task to download at a time you change from Executors.newScheduledThreadPool(10) to Executors.newScheduledThreadPool(1)
Edit: I'll leave my previous answer but update it with a solution to submit a task to start exactly 1 minute after the previous task completes. You would use two ExecutorServices. One to submit to the scheuled Executor and the other to do the timed executions. Finally the first Executor will wait on the completion and continue with the other tasks queued up.
ExecutorService e = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1)
public void submitTask(final Runnable r){
e.submit(new Runnable(){
public void run(){
ScheduledFuture<?> future= scheduledService.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
future.get();
}
});
}
Now when the future.get(); completes the next Runnable submitted through submitTask will be run and then scheduled for a minute. Finally this will work only if you require the task to wait the 1 minute even if there is no other tasks submitted.
I think this would be a wrong way of going about the problem. A bit more logical way would be to create "download job" objects which will be added to a job queue. Create a TimerTask which would query this "queue" every 1 minute, pick up the Runnable/Callable jobs and submit them to the ExecutorService.
You could use the built-in ExecutorService. You can queue up tasks as Runnables and they will run on the available threads. If you want only a single task to run at a time use newFixedThreadPool(1);
ExecutorService executor = Executors.newFixedThreadPool(1);
You could then append an artificial Thread.sleep at the beginning of each Runnable run method to ensure that it waits the necessary amount of time before starting (not the most elegant choice, I know).
The Java Concurrency package contains classes for doing what you ask. The general construct you're talking about is an Executor which is backed by a ThreadPool. You generate a list of Runables and send them to an Executor. The Executor has a ThreadPool behind it which will run the Runnables as the threads become available.
So as an example here, you could have a Runnable like:
private static class Downloader implements Runnable {
private String file;
public Downloader(String file) {
this.file = file;
}
#Override
public void run() {
// Use HttpClient to download file.
}
}
Then You can use it by creating Downloader objects and submitting it to an ExecutorService:
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (String file : args) {
executorService.submit(new Downloader(file));
}
executorService.awaitTermination(100, TimeUnit.SECONDS);
}
It is maybe not the best solution but here is what I came up with thanks to the answer of John Vint. I hope it will help someone else.
package tests;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class RunnableQueue
{
private long waitTime;
private TimeUnit unit;
ExecutorService e;
public RunnableQueue(long waitTime, TimeUnit unit) {
e = Executors.newSingleThreadExecutor();
this.waitTime = waitTime;
this.unit = unit;
}
public void submitTask(final Runnable r){
e.submit(new Runnable(){
public void run(){
Thread t = new Thread(r);
t.start();
try {
t.join();
Thread.sleep(unit.toMillis(waitTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
public static void main(String[] args) {
RunnableQueue runQueue = new RunnableQueue(3, TimeUnit.SECONDS);
for(int i=1; i<11; i++)
{
runQueue.submitTask(new DownloadTask(i));
System.out.println("Submitted task " + i);
}
}
}