How to properly multi-thread a collection of independent tasks? - java

I'm using this code to divide up a few hundred tasks between different CPU cores.
final List<Throwable> errors = Collections.synchronizedList(Lists.<Throwable>newArrayList());
final ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (...) {
pool.execute(new Runnable() { #Override public void run() {
try {
// TASK HERE
} catch (Throwable e) {
errors.add(e);
}
}});
}
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!errors.isEmpty()) throw Exceptions.wrap(errors.get(0)); // TODO multi-exception
It works, but it's not nice.
There is no version of awaitTermination without timeout, which is what I want.
I need to do my own error collecting.
What is the proper/common way to do this?

The point of a thread pool is to reuse threads. You should create it on application startup, outside of your code that creates tasks, and inject it. There is no need to shut down the pool after adding tasks. You do that when your application is shutting down.
To run a collection of tasks, use ExecutorService.invokeAll. To get the results afterwards, call get on each of the returned Futures. It will rethrow any exception that the task threw, so you can collect it afterwards.

You can use a future to do the error handling:
final List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < 5; i++) {
futures.add(pool.submit(new Runnable() { #Override public void run() {
// TASK HERE
}}));
}
for (Future f : futures) {
try {
f.get();
} catch (ExecutionException e) {
//something bad happened in your runnable
}
}
//when you are done with the executor
pool.shutdown();
try {
pool.awaitTermination(1000, TimeUnit.DAYS); // wait "indefinitely"
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

I think you need to submit each Runnable, get a Future back, and then call get() on each Future.
When you call get(), you'll either get the result of the Runnable, or the exception that it encountered.

Related

Re-execute Callable if it fails

Having an ExecutorService that executes a Callable that is supposed to be always running, what is the best implementation to relaunch it when an error happens?
Currently my source code looks something like this:
Future<Void> future = executorService.submit(new AlwaysOnlineCallable(config));
try {
future.get();
} catch (Exception e) {
//TODO thinking on execcuting the callable here
e.printStackTrace();
}
For what I've seen, cases like this are generally treated with runables.
Why not simply:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit((Runnable) () -> {
while (true) {
try {
...
} catch (Exception e) {
// log
}
}
});
There doesn't seem to be any need for a Callable or a Future.

Rethrowing exception from one thread to another

I have a scenario where I want one thread to do some looped operations and second (main) thread to do some other cyclic work while first thread is still doing its job.
My idea was to use CountDownLatch and await until it is finished in the main thread:
public void process() {
CountDownLatch countDownLatch = new CountDownLatch(10_000);
Future<?> future = Executors.newSingleThreadExecutor().submit(() -> {
for (int i = 0; i < 10_000; i++) {
// do some stuff
countDownLatch.countDown();
}
});
try {
while (!countDownLatch.await(5, SECONDS)) {
// do some other stuff...
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
The problem is sometimes an exception can be thrown in the first (future) thread and in such case it doesn't make sense to continue executing the code in the main thread as well.
I was thinking about assigning the reference of such exception (thrown from the first thread) to volatile field and doing a null check on this field in main's thread loop to see if it should continue looping:
private volatile Exception innerException;
public void process() {
CountDownLatch countDownLatch = new CountDownLatch(10_000);
Future<?> future = Executors.newSingleThreadExecutor().submit(() -> {
try {
for (int i = 0; i < 10_000; i++) {
// do some stuff
countDownLatch.countDown();
}
} catch (Exception e) {
this.innerException = e;
throw e;
}
});
try {
while (!countDownLatch.await(1, SECONDS)) {
// do some other stuff... but it doesn't make sense to continue
// if 'future' has thrown an exception, so let's rethrow it:
if (innerException != null) {
throw innerException;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("Something bad happened in the 'future'! : ", e);
}
}
I'm wondering if this is a good (safe?) idea or maybe there are some better ways to solve that kind of problem?
Appreciate any help on this one, thanks!
You can synchronize on the completion of the future using future.get. If the Runnable/Callable throws an exception, the future.get will throw an ExecutionException. You can get rid of the CountDownLatch completely.

Running a thread for some fixed time and killing it if time is out

I want to run a thread for some fixed amount of time.
If it is not completed within that time, I want to either kill it, throw some exception, or handle it in some way. How can this be done?
You should use an ExecutorService:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new Task());
try {
System.out.println("Started");
Integer retval = future.get(10, TimeUnit.SECONDS)); // you can choose your desired time here
System.out.println("Finished");
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("Timeout happened");
// handle termination here
}
executor.shutdownNow();
And your Callable can look something like this:
class Task implements Callable<Integer> {
#Override
public String call() throws Exception {
// some code here
return 0;
}
}

Shut down two instances of ExecutorService

I need to properly shut down two instances of Executor Service in one method.
Here's my simplified code:
ExecutorService executor1 = Executors.newSingleThreadExecutor();
ScheduledExecutorService executor2 = Executors.newSingleThreadScheduledExecutor();
// logic here
executor1.shutdown();
executor2.shutdown();
try {
if (!executor1.awaitTermination(1, TimeUnit.SECONDS)) {
executor1.shutdownNow();
}
} catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
try {
if (!executor2.awaitTermination(1, TimeUnit.SECONDS)) {
executor2.shutdownNow();
}
} catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
InterruptedException is converted to IllegalStateException as I don't expect any interruptions here and this would mean my application went into illegal state.
I see one flaw in this solution - whenever first executor while shutting down throws exception, the second executor won't be properly closed. What should be correct approach here? How to safely close two instances of ExecutorService?
I'd rather like to avoid nested try-finally blocks, as I might need to add third executor service and code would become unmanageable.
As for a similar situation:
Apache Commons IO has a closeQuietly() that closes streams (or rather any Closeable) while ignoring any exception during close.
public void shutdownQuietly(ExecutorService executor)
{
try {
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException ex) {
/* IGNORE */
}
}
If you need those exception, you can try some slightly more evil trickery:
class MultiExecutorShutdown
{
private final List<InterrupedException> exceptions = new ArrayList<>();
public void shutdown(ExecutorService service)
{
try {
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException ex) {
exceptions.add(ex);
}
}
public Optional<InterruptedException> getLastException()
{
if (exceptions.isEmpty()) {
return Optional.empty();
} else {
return exceptions.get(exceptions.size() - 1);
}
}
public Optional<InterruptedException> getFirstException()
{
if (exceptions.isEmpty()) {
return Optional.empty();
} else {
return exceptions.get(0);
}
}
}
[...]
MultiExecutorShutdown multiShutdown = new MultiExecutorShutdown();
multiShutdown.shutdown(executor1);
multiShutdown.shutdown(executor2);
multiShutdown.shutdown(executor3);
Optional<InterruptedException> exception = multiShutdown.getLastException();
// alternative:
// Optional<InterruptedException> exception = multiShutdown.getFirstException();
if (exception.isPresent()) {
throw new IllegalStateException(exception.get());
}
If you also need the executor which failed, you can also modify MultiExecutorShutdown to keep an (ordered) map ExecutorService -> Exception.
You can also push the throw into MultiExecutorShutdown itself, making it even more usable. And finally the whole thing can --of course-- be abstracted so that it takes a functional, calls that and records any exceptions thrown.

TimeoutTask using ExecutorService

I have implmented a TimeoutTask using ExecutorService. In the below method I am submitting the TimeoutTask and if it is timed out in a given time, I cancel the task and shuts down the executor.
private boolean waitForProcessToBeCompleted(long timeOut) {
boolean result = false;
ExecutorService executor = Executors.newSingleThreadExecutor();
// Create a FutureTask which will be run
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(new TimeoutTask());
executor.submit(futureTask); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
}
It is running very well and I don't have any issue.
However, I would like to know whether this is the best code design. I was just wondering if it could have been better to use a Future returned by ExecutorService.submit() to get the return value of the Callable or to time out the TimeoutTask. e.g.
Future<?> futureTask = executor.submit(new TimeoutTask()); // Run the FutureTask
try {
result = futureTask.get(timeOut, TimeUnit.MILLISECONDS); // Check if FutureTask completed in the given time
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
futureTask.cancel(true);
result = true; // Return True only when timed out
} finally {
executor.shutdownNow(); // Stop the executor
}
return result;
I am using JDK7.
I would prefer using CountDownLatch:
List<List<String>> elements = MyPartition.partition(bigObjectList, size);
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newSingleThreadExecutor();
CountDownLatch doneSignal = new CountDownLatch(10);
for(List<String> l: elements) {
ReadTask worker = new ReadTask(doneSignal, l);
tasks.add(executor.submit(worker));
}
long timeout = 10000;
doneSignal.await(timeout, TimeUnit.SECONDS);
boolean notFinished = false;
if(doneSignal.getCount() > 0) {
for(Future<?> fut : tasks) {
if(!fut.isDone()) {
System.out.println("Sub Thread " + fut + " has not finshed!");
fut.cancel(true);
notFinished = true;
}
}
}
If you look at the code of futureTask.cancel, you'll see that it just attempts to interrupt the thread which is executing the task. This interruption may work if the task regullary checks the interruption flag, explicitly or implicitly (via calling to sleep() or wait()). In Java, there is no other safe way to stop execution of a method.
So, you can implement the same functionality without creating each time a separate single-threaded executor. Instead, execute the TimerTask from within the waitForProcessToBeCompleted method. In order to be notified of timeout, submit a watching task to a SheduledExecutorService. The watching task should interrupt the thread which executes the TimerTask. If the task is completed before timeout, cancel the watching task.
This way you need a SheduledExecutorService, but it consumes very little processor cycles, and can be reused all over the application.
The invokeAll method on ExecutorService can be used to automatically cancel tasks that exceed the timeout. This lets you cancel tasks without shutting down the threadpool (which let's you re-use the same threadpool for other things if you choose).
private boolean waitForProcessToBeCompleted(long timeOut) {
ExecutorService executor = Executors.newSingleThreadExecutor();
List<FutureTask> tasks = new ArrayList<>();
tasks.add(new SomeFutureTaskThing()));
List<Future<Boolean>> results;
try {
results = executor.invokeAll(tasks, timeOut, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupt status.
return null;
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
}
Future<Boolean> result = results.get(0);
try {
return result.get();
} catch (CancellationException e) {
System.err.println("Timed out");
return null;
}
}

Categories

Resources