I'm feeding threads into an ExecutorService.
These threads are manipulating some data, and if there's a conflict, the data object throws an exception, which is caught by the conflicting thread, which in turn aborts and does not complete execution.
When this happens, the aborting thread needs to be put back in the queue and fed back into the executor.
How can I tell if an exception was thrown, from the parent thread?
When you submit() a task on the ExecutorService you get a Future as a result. When the execution has finished you can call get() on that future. This will return the result if applicable, or it will throw an ExecutionException if the original task threw one. If you want the real exception object you can do getCause().
Also note that you would be putting a Task back into the service, that task is ran on a Thread which has not really terminated (just caught the exception and is waiting for a new one).
Here is an example usage (you can use Runnable if you don't care for the result).
Callable<String> myCallable = ...;
Future<String> future = myExector.submit(myCallable);
// Do something else until myCallable.isDone() returns true.
try {
String result = future.get();
}catch(ExecutionException e){
// Handle error, perhaps create new Callable to submit.
}
Related
I'm trying to write a process in Java that executes a series of tasks concurrently, waits for the tasks to be done, then tags the overall process as complete. Each task has its own information, including when the individual task is complete. I'm using an ExecutorService for the process, and have boiled down the essence of the process as follows:
List<Foo> foos = getFoos();
ExecutorService executorService = Executors.newFixedThreadPool(foos.size());
for (Foo foo : foos) {
executorService.execute(new MyRunnable(foo));
}
executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// log the error.
}
completeThisProcess();
Each of the MyRunnable objects has a run method that makes a webservice call, then writes the results of the call to the database, including the time the call completed. The completeThisProcess method simply writes the status of the whole process as complete along with the time the process completed.
The problem I'm having is that when I look in the database after the process has completed, the completeThisProcess method has apparently been able to execute before all of the MyRunnables have completed. I'm noticing that the times that are written from the completeThisProcess method are even occasionally upwards of 20-30 seconds before the last MyRunnable task has completed.
Is there anything there that is obviously wrong with the process I've written? Perhaps I'm not understanding the ExecutorService correctly, but I thought that the awaitTermination method should be ensuring that all of the MyRunnable instances have completed their run methods (assuming they complete without exception, of course), which would result in all the sub-tasks having completion times before the overall process's completion time.
If you want to wait for all the threads to return is then following method can be trusted.
Make your thread class implement Callable interface instead of Runnable (In case of Callable run method will return some value. Make it return threadName.
Create a list of Callable Objects and use invokeAll method which will wait for all threads to return. For the below code assume the thread class name to be MyCallable.
ExecutorService executorService = Executors.newFixedThreadPool(foos.size());
List<Callable> tasks = new ArrayList<>();
for (Foo foo : foos) {
tasks.add(new MyCallable(foo));
}
executorService.invokeAll(tasks);
invokeAll returns List of future objects if you want to make use of it.
OR
you can use CountDownLatch.
CountDownLatch cdl = new CountDownLatch(foo.size);
Make it count down in run method using cdl.countDown() method.
Use cdl.await after for loop and then it will wait untill cdl become zero.
Heading
I try to execute several tasks in parallel with a CompletionService. The problems arise, when i try to implement cancelation.
Here is a sketch of the code I use:
void startTasks(int numberOfTasks) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
CompletionService<TaskResultType> completionService = new ExecutorCompletionService<TaskResultType>(executor);
ConcurrentLinkedQueue<TaskResultType> results = new ConcurrentLinkedQueue<BenchmarkResult>();
ArrayList<Future> futures = new ArrayList<Future>();
for (int i = 0; i < numberOfTasks ; i++) {
TypeOfTask task = ... ;
Future future = completionService.submit(task);
futures.add(future);
}
boolean failed = false;
Throwable cause = null;
for (int i = 0; i < numberOfThreads; i++) {
try {
Future<TaskResultType> resultFuture = completionService.take();
TaskResultType result = resultFuture.get();
results.add(result);
} catch (ExecutionException e) {
failed = true;
cause = e.getCause();
/* cancel all other running tasks in case of failure in one task */
for (Future future : futures) {
future.cancel(true);
}
} catch (CancellationException e) {
// consume (planned cancellation from calling future.cancel())
}
}
executor.shutdown();
// code to throw an exception using cause
}
The tasks implement Callable.
When I now throw an exception in one of the tasks in most of the cases it works out fine, i.e. I immediately get the CancellationExceptions from the other tasks and the tasks finish immediately (lets call this case A). But sometimes (lets call this case B), some of the tasks finish first and then throw the CancellationException. Future.cancel(true) returned true in both cases for all tasks (except the one with the initial ExecutionException, because this one was already canceled).
I check for the interrupted flag with Thread.currentThread.isInterrupted(), in the tasks that do complete (i.e. the tasks where the cancelation is unsuccessful), the interrupted flag is set to false.
All that seems to be very strange behavior in my eyes. Anybody any idea what the problem could be?
Update
The best idea so far I have is, that somewhere deep within the code comprising the task (only some high level code is from myself) the interrupted status is consumed, e.g. by a catched InterruptedException which doesn't call Thread.interrupt() to reestablish the status. The exact time the interrupted flag is set by Future.cancel() might vary slightly due to scheduling of the threads, that would explain the inconsistent behavior. Would a consumed interrupted status explain the behavior of case B?
But sometimes, some of the tasks finish first and then throw the
CancellationException.
Could it be the case that you cancel a task, it's normally interrupted (in this state you may think that it returns a result, but for the CompletionService it's cancelled), the future is being returned by take(), you call future.get() and there is the CancellationException.
You could also have a look at Guava's Futures.allAsList, which seems to be doing a very similar thing:
Creates a new ListenableFuture whose value is a list containing the values of all its input futures, if all succeed. If any input fails, the returned future fails.
But sometimes, some of the tasks finish first and then throw the CancellationException. Future.cancel(true) returned true in both cases for all tasks (except the one with the initial ExecutionException, because this one was already canceled).
If your program was not finishing (or taking a long time to finish after an exception is thrown) then I suspect your problem is that one of the tasks is doing IO or otherwise blocked and is not checking for Thread.currentThread().isInterrupted(). So even though you have canceled the Future and the thread is interrupted, this doesn't get detected.
However, it seems like the program is finishing. So I'm not sure what the error case is here. If you catch an exception you call future.cancel(true) on all of the futures in the list. The one that threw and the ones that have already finished should all return false since they can't be canceled. The ones that returned true from cancel should have been interrupted.
For example. if the 2nd to last thread throws an exception then future.cancel(true) should only return true for the last thread running.
One thing to do is to remove the futures as they finish so you don't re-cancel already completed jobs. But all that might do is mask the issue you are seeing now:
Future<TaskResultType> resultFuture = completionService.take();
futures.remove(resultFuture);
Update:
It is highly possible that some code is swallowing the interrupt. It happens all of the time unfortunately. If some of the threads are not finishing immediately when they are canceled and are running to completion then this is probably what is happening.
I'm working on a project that has a thread pool to which it submits tasks. Each task is a chain, so to speak. When the task executes, it does what it needs to do, then checks the result. Each of these tasks contains a map of results (which is just an enum) and additional tasks. These are called within the same thread and the cycle repeats until there are no more tasks, at which point it goes back up the chain, adding each result to a collection and returning that to the main thread. Q&D example:
public abstract class MyCallable implements Callable<MyResponse> {
private Map<ResponseEnum, List<MyCallable>> callbacks;
public List<MyResponse> call() {
List<MyResponse> resp = new ArrayList<MyResponse>();
try{
//Run the process method and collect the result
MyResponse response = process();
List<MyCallable> next = callbacks.get(response.getResult());
if (next != null && !next.isEmpty()){
//Run within same thread, return results
for (MyCallable m : next){
resp.addAll(m.call();
}
return resp;
} else {
//No more responses, pass them back up the chain
resp.add(response);
return list;
}
//Anything goes wrong, we catch it here and wrap it in a response
} catch (Exception e){
resp.add(new MyExceptionResponse(e));
return resp;
}
}
//Implemented by all child classes, does the actual work
public abstract MyResponse process() throws Exception;
Bear in mind that this is also a prototype that I have not yet really tested out, so I'm aware that this may not be perfect or necessarily completely feasible.
The concern I have is this: A task is added to the thread pool and begins execution. In the main thread, a Future is created and a .get(N, TimeUnit) is called on it to retrieve the result. What if that task times out? We get a TimeoutException. Now, within a try/catch block I could cancel the Future, but is there any way for me to cancel the Future and extract the results, at least as far as they go? Three tasks may have executed and returned results before the the fourth stalled out. The try/catch in MyCallable should return a result and push it back up the chain if there's an exception (Ie, InterruptedException when .cancel(true) is called), but is it possible for me to get that result?
Of course, if I'm going about this completely wrong in the first place, that would also be good to know. This is my first big foray into multithreading.
EDIT: Okay, with that in mind, a wrapper has been placed around the MyCallable class. The wrapper implements Callable and returns the collection. The collection is passed down the chain of MyCallable objects and the results added, so if the Future.get times out, we can retrieve the collection and get the partial results.
However, this brings up a potential race condition. If the current MyCallable being invoked is waiting for an external service, then the Future.cancel(true) operation will cause an InterruptedException within MyCallable. This is caught and the exception is wrapped in a response object and added to the collection. The thing is, if the main thread cancels the Future, synchronizes on the wrapper or the collection in the wrapper, and then gets the collection, will that create a race condition between the getting of the collection and the try/catch block in MyCallable adding the wrapped exception to the collection? Or will the main thread wait for the catching of the exception and then execute the next line?
At the point when you get your TimeoutException, the task submitted to the Executor Service is merrily going forth on its way: it is only your waiting which has received the exception. That presumably means that the result map is still being populated.
What you could do is is use a concurrent map and safely extract whatever results are present after the timeout has occurred.
Below is the piece of code that submits a job.. Let's say I have 3 threads running. how does the get method wait and obtain the appropriate thread results.
Future<?> result = threadPool.submitTasks(new Callable<T>() {
public T call() throws Exception {
// do something
}
});
anyType = (T) result.get();
Or Lets say I have Task A resulted 1 and Task B resulted 2.. When it comes to get method, what is the guarantee that it returns the correct values?
Your submitted task (in this case the Callable) is wrapped into the instance of the returned Future. In essence, the Future is directly related to the task it was created for, and not any other task.
Internally, when calling get, the future will attempt to acquire a lock that it shares in common with its wrapped task. Once acquired, it then queries the status of the task in order to determine what to do next:
Throw an exception if the Future was cancelled, or if the underlying task generated an exception
Otherwise, return the result that was generated by the task.
This is broadly how it works, there are several implementations of Future and they all have different internal logic.
You're assuming there is a guarantee they will receive the correct output. This is a question of implementing Thread safe code.
Often, to make an implementation thread safe, you will lock it from use with some sort of flag. This will indicate to other threads that they can not use it.
I am using several threads to do some heavy (and error-prone) processing on a large data set. I require all threads to finish execution, regardless of whether they throw an exception or terminate normally (no value is returned), before the program can continue. I am using a CountDownLatch to achieve this, and an ExecutorService to actually run the jobs. I want the worker threads (let's call them JobManager-s for the sake of argument) to notify the latch even if they throw an exception. A JobManager can take anywhere between a second and an hour to complete, and may fail at any time. The idea is to invoke the "finalizer" method of JobManager if an exception is thrown. Now, the ExecutorService likes to catch exceptions or to conceal the true origin of the ones it does not. I have though of a few ways around this, neither of which is satisfactory:
Use ExecutorService#execute(Runnable r) rather than submit(Runnable r). I can do that since I do not care about the return value of the JobManager. I have provided a custom ThreadFactory, which attaches an UncaughtExceptionHandler to each newly created thread. The problem with this approach is that when UncaughtExceptionHandler#uncaughtException(Thread t, Throwable e) is invoked, t's Runnable is of type ThreadPoolExecutor$Worker, and not of type JobManager, which prevents me from invoking the "finalizer" method.
Use a custom ExecutorService and override the afterExecute(Runnable r, Throwable t) method. This suffers from the same problem as 1.
Wrap the whole JobManager#doWork() in a catch statement and use the return value to indicate if an exception was thrown. I can then submit the jobs and use FutureTask#get() to decide if an exception was thrown. I do not like this solution because I feel return codes the wrong tool when you have an elaborate exception mechanism. Moreover, get() will wait (unless interrupted), which means I cannot handle errors in other threads immediately.
Get rid of the CountDownLatch. Store all Futures in a list and repeatedly poke in until I am satisfied with the states. This might work, but feels like a dirty hack.
Any suggestions are greatly appreciated.
As far as I understand, you can use a simple try-finally block:
public class JobManager {
public void doWork() {
try {
...
} finally {
countDownLatch.countDown();
}
}
}