I am using the ExecutorService to create a Thread Pool. After adding all tasks, the threadPool is shutdown.
Now the Java Doc for Future.get() says
Waits if necessary for the computation to complete, and then retrieves its result.
I am not able to understand the "if necessary" part. When does the future.get() method wait and how much time will it wait?
If it waits till the thread execution is over, is there a need threadPool.awaitTermination?
ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads);
List<Future<?>> futureObjList = new ArrayList<Future<?>>();
for (int i = 0; i < numberOfThreads; i++) {
...
Future<?> future = threadPool.submit(myThread);
futureObjList.add(future);
...
}
threadPool.shutdown();
for(Future<?> future : futureObjList){
try {
future.get();
} catch (Exception e1) {
//if any thread fails, all other thread should stop their execution.
threadPool.shutdownNow();
}
}
try {
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e1) {
throw e1;
}
The "if necessary" just means that the get() method might block or not depending if the thing that is happening in the Runnable or Callable is already done or not.
Suppose you submit a Callable to an executor service. The Callable takes 2 seconds to execute.
If you call get() 1 second after the submit, the get() will block for 1 more second. However, if you would have called get() 5 seconds after the submit, the get() would not block and immediately return.
future.get()
will block calling thread, if method .call of Callable haven't returned a result by the time .get is invoked. If you iterate over every future, then by the time you exit a for-loop, all threads have finished executing.
You will have to call threadPool.awaitTermination() before getting the results from the threads as awaitTermination will wait for all the threads to complete computation. After all threads have completed you can be sure that future.get() will not block as it has completed its execution. future.get() will wait until the thread finishes execution unless you specify a timeout.
Related
Lock sharedLock = new ReentrantLock();
Condition condition = lock.newCondition();
main thread:
sharedLock.lock();
childThread.start();
condition.await(5, TimeUnit.SECONDS);
sharedLock.unlock();
child thread:
sharedLock.lock();
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
condition.signal();
sharedLock.unlock();
Suppose child thread send a network request and wait for response, I want main thread wait at most 5 seconds, if timeout, retry the request. but when the await() timeout, it cannot acquire lock because child thread still hold it, so it still wait the lock until child thread release it, which takes 10 seconds.
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
This is not how your are supposed to do it, you are supposed to:
Create an ExecutorService (thread pool) for that you should check the methods of the class Executors to choose the best one in your case but Executors.newFixedThreadPool is a good start
Submit your task as a FutureTask to the thread pool
Then call get with a timeout
Manage properly the TimeoutException
Here is how it could be done:
// Total tries
int tries = 3;
// Current total of tries
int tryCount = 1;
do {
// My fake task to execute asynchronously
FutureTask<Void> task = new FutureTask<>(
() -> {
Thread.sleep(2000);
return null;
}
);
// Submit the task to the thread pool
executor.submit(task);
try {
// Wait for a result during at most 1 second
task.get(1, TimeUnit.SECONDS);
// I could get the result so I break the loop
break;
} catch (TimeoutException e) {
// The timeout has been reached
if (tryCount++ == tries) {
// Already tried the max allowed so we throw an exception
throw new RuntimeException(
String.format("Could execute the task after %d tries", tries),
e
);
}
}
} while (true);
How can I achieve my requirement that main thread wait child thread's
signal, but have a bounded timeout?
Here is how you can achieve your requirements:
Main Thread:
lock.lock();
try {
childThread.start();
condition.await(5, TimeUnit.SECONDS);
} finally {
sharedLock.lock();
}
The child thread:
try {
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
} finally {
// Here we notify the main thread that the task is complete whatever
// the task failed or not
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
As you can see to work, the task must not be performed within the critical section, we only acquire the lock to notify the main thread nothing more. Otherwise if you execute the task within the critical section after the timeout the main thread will still need to acquire the lock once again and since the lock is actually owned by the child thread, it will need to wait anyway until the end of the task which makes the timeout totally useless.
NB: I renamed sharedLock to lock as a ReentrantLock is an exclusive lock not as shared lock, if you need a shared lock check the class Semaphore to define the total amount of permits.
Your code can be simplified with intrinsic lock.
Object sharedObj = new Object();
main thread:
synchronized (sharedObj) {
int retryCount = 0;
while (retryCount < maxRetry) {
sharedObj.wait(5000);
retryCount++;
}
}
child thread:
synchronized (sharedObj) {
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
sharedObj.notify();
}
java condition await timeout but can't return
That's because the lock must be released so wait/await can return. So your child thread should be like:
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
synchronized (sharedObj) {
sharedObj.notify();
}
Java's wait/notify is usually used to solve producer-consumer problem. And usually sharedObj shouldn't be holded for too long. Then your main thread can hold the lock again when the wait timeout.
Take a look at an in-production example: hadoop/hdfs/DFSOutputStream.java
The logic is simple, the producer creates packet and put it in dataQueue
// takes a long time to create packet
synchronized (dataQueue) {
dataQueue.addLast(packet);
dataQueue.notifyAll();
}
The consumer wait while dataQueue is empty:
synchronized (dataQueue) {
while ((!shouldStop() && dataQueue.size() == 0 &&... ) {
try {
dataQueue.wait(timeout);
} catch (InterruptedException e) {
LOG.warn("Caught exception", e);
}
doSleep = false;
now = Time.monotonicNow();
}
As you can see, the dataQueue are unlocked for most of the time!
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
If your child thread are mostly in a loop, your Main thread can set a isRunning flag to make child thread stop by itself. If your child thread are mostly blocking by an I/O operation, your Main thread can interrupt the child thread.
The sharedObj is used for coordination and protects sharedObj. If there's other resources should be protected, you have 2 choices:
1. If the operation on the resource is quick, like ackQueue in DFSOutputStream.java, protect it together inside the sharedObj.
2. If the operation on the resource is time-consuming, do it and protect it outside the sharedObj.
The valid confusion in the question is because the "Thread.sleep(10)" is done inside the lock block. When await(long time, TimeUnit unit) has to return because of timeout, it still needs the lock. So, as suggested in the other answer the long running task should not be inside the lock for it to work properly.
But it would be nice to have proper documentation stressing this fact. For example, if we await(5, TimeUnit.SECONDS) i.e wait for 5 seconds and the lock is available 10 seconds after the call, it will still return false even though the lock is available now at the moment of return.
I want to set timeouts for threads which are executed within a thread pool. At the moment I have following code:
ExecutorService executor = Executors.newFixedThreadPool(8);
for(List<String> l: partition) {
Runnable worker = new WorkerThread(l);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
The code just splits a big list of objects into sublists and process these sublist within single threads. But this is not the point.
I want to give each single thread in the thread pool a timeout. For only one thread in the pool I found following solution:
Future<?> future = null;
for (List<String> l : partition) {
Runnable worker = new WorkerThread(l);
future = executor.submit(worker);
}
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
But this would not work for more than one thread. Maybe I have to put each thread in a List<Future> list and iterate over this list and set a timeout for each future object?
Any suggestions?
EDIT AFTER USING CountDownLatch:
CountDownLatch doneSignal = new CountDownLatch(partition.size());
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newFixedThreadPool(8);
for (List<String> l : partition) {
Runnable worker = new WorkerThread(l);
tasks.add(executor.submit(doneSignal, worker));
}
doneSignal.await(1, TimeUnit.SECONDS);
if (doneSignal.getCount() > 0) {
for (Future<?> fut : tasks) {
if (!fut.isDone()) {
System.out.println("Task " + fut + " has not finshed!");
//fut.cancel(true) Maybe we can interrupt a thread this way?!
}
}
}
Works good so far.
So next question is how to interrupt a thread which is timed out? I try fut.cancel(true) and add following construct in some critical loops in the worker thread:
if(Thread.interrupted()) {
System.out.println("!!Thread -> " + Thread.currentThread().getName() + " INTERRUPTED!!");
return;
}
So the worker thread is "killed" after the timeout. Is this a good solution?
Furthermore: Is it possible to get the name of the thread which timed out over the Future interface? At the moment I have to print out the name in the if condition of the Thread.interrupted() construct.
Thanks for help!
Regards
Have you seen this? ExecutorService.invokeAll
It should be exactly what you want: Invoke a bundle of workers and have them timeout if taking too long.
EDIT after comment - (new idea):
You can use a CountDownLatch to wait for the tasks to finish AND timeout via await(long timeout, TimeUnit unit)!
You can then even do a shutdownNow and see which tasks have taken too long ...
EDIT 2:
To make it clearer:
Have a CountDownLatch be count down by each Worker, when finished.
In the main execution thread await with timeout on said latch.
When that call returns, you can check the Latches's count to see if there has been the timeout hit (if it is >0).
a) count = 0, all tasks finished in time.
b) if not, loop the Futures and check their isDone. You don't have to call shutdown on the ExecutorService.
Call shutdown if you do not need the Executor any longer.
Note: Workers can finish in the meantime between the timeout and calling their Future's isDone().
Future future = executorService.submit(callable)
future.get(timeout, unit)
For more information see this link.
I want execute a search method by java main and want to implement the
Time out by which search method returns otherwise it will throw a time out message.
How can I achieve this time out functionality using thread or timer class?
One approach would be to submit your search task to an executor, and call get(timeout); on the returned future - in essence:
create a Callable with your task
run it with a timeout
if it times out, cancel it - for the cancellation to work, your Callable needs to react to an interruption
Callable<SearchResult> task = ...;
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<SearchResult> f = executor.submit(task);
SearchResult result = null;
try {
result = f.get(2, TimeUnit.SECONDS); //2 seconds timeout
return result;
} catch (TimeOutException e) {
//handle the timeout, for example:
System.out.println("The task took too long");
} finally {
executor.shutdownNow(); //interrupts the task if it is still running
}
Im using the ExecutorService in Java to invoke Threads with invokeAll(). After, I get the result set with future.get(). Its really important that I receive the results in the same order I created the threads.
Here is a snippet:
try {
final List threads = new ArrayList();
// create threads
for (String name : collection)
{
final CallObject object = new CallObject(name);
threads.add(object);
}
// start all Threads
results = pool.invokeAll(threads, 3, TimeUnit.SECONDS);
for (Future<String> future : results)
{
try
{
// this method blocks until it receives the result, unless there is a
// timeout set.
final String rs = future.get();
if (future.isDone())
{
// if future.isDone() = true, a timeout did not occur.
// do something
}
else
{
// timeout
// log it and do something
break;
}
}
catch (Exception e)
{
}
}
}
catch (InterruptedException ex)
{
}
Is it assured that I receive the results from future.get() in the same order I created new CallObjects and added them to my ArrayList? I know, Documentation says the following:
invokeAll(): returns a list of Futures representing the tasks, in the same sequential order as produced by the iterator for the given task list. If the operation did not time out, each task will have completed. If it did time out, some of these tasks will not have completed. But I wanted to make sure I understood it correctly....
Thanks for answers! :-)
This is exactly what this piece of the statement is saying:
returns a list of Futures representing the tasks, in the same
sequential order as produced by the iterator for the given task list.
You will get the Futures in the exact order in which you inserted the items in the original list of Callables.
As per the documentation you will get the futures in same order.
Future object is just a reference of the task.
Future#get() is blocking call.
For ex
We have submitted 4 tasks.
Task 1 - > Completed
Task 2 --> Completed
Task 3 --> Timed Out
Task 4 --> Completed
As per our code
for (Future future : futures) {
future.get(); }
For 1&2 second task it will return immediately. We will wait for the third task will get completed. Even 4th task completed , iteration is waiting in third task . Once third task completed or timed wait expire on that time only iteration will continue.
As the title showed, If Future.get(timeout) timeout, does the thread continue running,
ExecutorService executor = Executors.newFixedThreadPool(n);
Callable<Object> task = new Callable<Object>() {
public Object call() {
//...
}
}
Future<Object> future = executor.submit(task);
try {
Object result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
// handle the timeout
}
If the thread continue to run and get blocked due to some IO, etc, then when the threadpool get full, not new task can be sumitted, which means the trheadpool gets stuck, since all the threads in the pool are blocked, right?
The call to future.get(..) will block the thread running it for up to 5 seconds. The task executed by the thread pool will be unaffected, and will continue running until a graceful termination / exception / interruption.
Regarding the submission of new tasks when the thread pool is in full capacity, in your case the tasks WILL be submitted (releasing the submitter thread immediately), but will wait in the thread pool queue for execution. The API documentation of Executors.newFixedThreadPool(..) specifies this clearly.
Right, underlaying thread will be live until IO thrown an exception or ended.