How to release resource in canceled CompletableFuture - java

Uscase
Suppose we run execution with CompletableFuture.runAsync(..) and in runnable we have try-with-resources block (we are using some resource that should be closed whatever happens), and at some point when execution is not finished in try block we cancel the completable future... altough execution is stopped the resource that should be closed is not closed the close() of AutoClosable is not called...
Question
Is that a java issue or there is a way to do that properly? without hacky workarounds like using futures (that support interruption etc..), and if its expected behaviour how should one handle similar situation when non interruptable CompletableFuture is canceled...?
The Code
public class AutoClosableResourceTest {
public static class SomeService{
public void connect(){
System.out.println("connect");
}
public Integer disconnect(){
System.out.println("disconnect");
return null;
}
}
public static class AutoClosableResource<T> implements AutoCloseable {
private final T resource;
private final Runnable closeFunction;
private AutoClosableResource(T resource, Runnable closeFunction){
this.resource = resource;
this.closeFunction = closeFunction;
}
public T get(){
return resource;
}
#Override
public void close() throws Exception {
closeFunction.run();
}
}
#Test
public void testTryWithResource() throws InterruptedException {
SomeService service = new SomeService();
CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {
try (AutoClosableResource<SomeService> resource = new AutoClosableResource<>(service, service::disconnect)) {
resource.get().connect();
while (true) {
Thread.sleep(1000);
System.out.println("working...");
}
} catch (Exception e) {
e.printStackTrace();
}
});
Thread.sleep(2500);
async.cancel(true);
Thread.sleep(2500);
}
}
this will produce
connect
working...
working...
working...
working...
as you can see it does not call cancel() and leaves resource opened...

It seems you have difficulties in understanding what the purpose of CompletableFuture is. Have a look at the first sentence of its class documentation:
A Future that may be explicitly completed (setting its value and status), …
So unlike FutureTask which is completed by the thread executing its run method, a CompletableFuture can be completed by any thread which will set its value/status at an arbitrary point of time. The CompletableFuture doesn’t know which thread will complete it and it doesn’t even know whether there is a thread currently working on its completion.
Therefore the CompletableFuture can not interrupt the right thread when being canceled. That’s a fundamental part of its design.
If you want a worker thread that you can interrupt you are better off using FutureTask/ThreadPoolExecutor. The task scheduled that way may still complete a CompletableFuture at its end.

The following code will be stuck in an infinite loop. Calling async.cancel will not communicate with the following loop its desire to stop.
while (true) {
Thread.sleep(1000);
System.out.println("working...");
}
The test case exits because the thread stuck in this loop is not a daemon thread.
Replace the while loop check with the following, which checks the isCancelled flag on each iteration. Calling CompletableFuture.cancel() will mark the future as cancelled, but it does not interrupt the thread that was started via runAsync.
while (isCancelled()) {
Thread.sleep(1000);
System.out.println("working...");
}

You could use the "complete" method of the CompletableFuture to stop the thread.
Below a simple code to show the behaviour:
package com.ardevco;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureTest3 {
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(5);
CompletableFuture<Integer> longRunningcompletableFuture = CompletableFuture.supplyAsync(() -> {
for (int i = 0; i < 1; i--) {
System.out.println("i " + i);
sleep();
}
return 1; // we will newer reach this line so the thread will be stuck
});
CompletableFuture<Integer> completor = CompletableFuture.supplyAsync(() -> {
System.out.println("completing the longRunningcompletableFuture");
longRunningcompletableFuture.complete(1000);
System.out.println("completed the longRunningcompletableFuture");
return 10;
});
Thread.sleep(10000);
System.out.println("completor...");
int i = completor.get();
System.out.println("completor i:" + i);
System.out.println("completor...");
System.out.println("completableFutureToBeCompleted2...");
int i2 = longRunningcompletableFuture.get();
System.out.println("completableFutureToBeCompleted2: " + i2);
System.out.println("completableFutureToBeCompleted2...");
}
private static void sleep() {
try {Thread.sleep(1000);}catch (Exception e) {}
}
}
output:
i 0
completing the longRunningcompletableFuture
completed the longRunningcompletableFuture
i -1
i -2
i -3
i -4
i -5
i -6
i -7
i -8
i -9
i -10
completor...
completor i:10
completor...
completableFutureToBeCompleted2...
completableFutureToBeCompleted2: 1000
completableFutureToBeCompleted2...

Though there is an answer marked as correct, the reason is quite different - please see documentation for CompletableFuture.cancel(mayInterruptIfRunning) method and read the article CompletableFuture can't be interrupted to understand the problem better.
This issue is addressed in my Tascalate Concurrent library, the changes to your code should be:
From
CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {
...
});
To
Promise<Void> async = CompletableTask.runAsync(() -> {
...
}, someExplicitExecutor);
...and you will get expected behavior (executor thread is interrupted, AutoClosable is closed, async is completed with CancellationException).
You can read more about the library in my blog

I also face this problem in Java 8 SE. For me, it's important not to use third-party libraries.
cancel(mayInterruptIfRunning) this value has no effect in this implementation because interrupts are not used to control processing.
The idea is to use Thread.interrupt() when calling cancel(), but only for Runnable.
/** Enable and disable the interrupt */
private static class Interruptor {
volatile boolean interrupted;
volatile Runnable interrupt;
/** Enable interrupt support */
synchronized boolean start() {
if (interrupted) {
return false;
}
Thread runThread = Thread.currentThread();
interrupt = () -> {
if (runThread != Thread.currentThread()) {
runThread.interrupt();
}
};
return true;
}
/** Interrupt Runnable */
synchronized void interrupt() {
if (interrupted) {
return;
}
interrupted = true;
if (interrupt != null) {
interrupt.run();
interrupt = null;
}
}
/** Disable interrupt support */
synchronized void finish() {
interrupt = null;
}
}
/** CompletableFuture with interrupt support */
public static CompletableFuture<Void> runAsyncInterrupted(Runnable run) {
final Interruptor interruptor = new Interruptor();
Runnable wrap = () -> {
if (!interruptor.start()) { // allow interruption
return; // was canceled before the thread started
}
try {
run.run(); // can be interrupted
} finally {
interruptor.finish(); // can no longer be interrupted
}
};
CompletableFuture<Void> cfRun = CompletableFuture.runAsync(wrap);
// here is caught "CompletableFuture.cancel()"
cfRun.whenComplete((r, t) -> {
if (t instanceof CancellationException) {
interruptor.interrupt();
}
});
return cfRun;
}
Example of use
Runnable mySlowIoRun = () -> {
try {
InputStream is = openSomeResource(); // open resource
try {
// there may be problem (#1) with reading,
// such as loss of network connection
int bt = is.read();
// ..
// .. some code
} finally {
is.close(); // problem (#2): releases any system resources associated with the stream
}
} catch (Throwable th) {
throw new RuntimeException(th);
}
};
CompletableFuture<Void> cf = runAsyncInterrupted(mySlowIoRun);
try {
cf.get(5, TimeUnit.SECONDS); // 5 sec timeout
} catch (Throwable th) {
cf.cancel(true); // cancel with interrupt mySlowIoRun
throw th;
}

So this is a generalization of how I typically handle the problem.. pass-in a cancellable state, and close resources IMMEDIATELY after the open state.
private static BufferedReader openFile(String fn) {
try {
return Files.newBufferedReader(Paths.get(fn));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
static class Util {
static void closeQuietly(AutoCloseable c) {
if (c == null) return;
try {
c.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static <T extends AutoCloseable, R> R runThenCloseQuietly(T c, Function<T,R> cb) {
try {
return cb.apply(c);
} finally {
closeQuietly(c);
}
}
static <T extends AutoCloseable, R> Optional<R> runThenCloseQuietlyCancellable(BooleanSupplier cancelled
, T c, Function<T,Optional<R>> cb) {
if (c == null) return Optional.empty(); // safe doesn't throw
try {
if (cancelled.getAsBoolean()) return Optional.empty(); // might throw, wrap for safety
return cb.apply(c); // might throw
} finally {
closeQuietly(c); // might throw, but at least we're closed
}
}
private static Optional<String> emptyString() {
return Optional.empty();
}
}
interface Cancellable {
boolean isCancelled();
void cancel();
}
static class CancellableAB implements Cancellable {
private final AtomicBoolean cancelled;
CancellableAB(AtomicBoolean cancelled) {
this.cancelled = cancelled;
}
#Override
public boolean isCancelled() {
return cancelled.get();
}
#Override
public void cancel() {
cancelled.set(true);
}
}
static class CancellableArray implements Cancellable {
private final boolean[] cancelled;
private final int idx;
CancellableArray(boolean[] cancelled) {
this(cancelled, 0);
}
CancellableArray(boolean[] cancelled, int idx) {
this.cancelled = cancelled;
this.idx = idx;
}
#Override
public boolean isCancelled() {
return cancelled[idx];
}
#Override
public void cancel() {
cancelled[idx]=true;
}
}
static class CancellableV implements Cancellable {
volatile boolean cancelled;
#Override
public boolean isCancelled() {
return cancelled;
}
#Override
public void cancel() {
this.cancelled = true;
}
}
/**
* The only reason this is a class is because we need SOME external object for the lambda to check for mutated
* cancelled state.
* This gives the added benefit that we can directly call cancel on the resource.
* We allow a cancellable to be passed in to CHAIN-IN cancellable state. e.g. if cancellation should affect MULTIPLE
* CompletableFuture states, we don't want other promises to tie references to this task.. So the cancellable
* object can be externalized.
*
* Normally you don't need this much genericism, you can directly implement a volatile 'cancel boolean'.
* But this allows you to create a C.F. task as a 3rd party library call - gives maximum flexibility to invoker.
*
*/
static class FooTask {
volatile Cancellable cancelled;
String fileName;
public FooTask(String fileName) {
this.fileName = fileName;
this.cancelled = new CancellableV();
}
public FooTask(String fileName, Cancellable cancelled) {
this.cancelled = cancelled;
}
public boolean isCancelled() {
return cancelled.isCancelled();
}
public void cancel() {
cancelled.cancel();
}
/**
* asynchronously opens file, scans for first valid line (closes file), then processes the line.
* Note if an exception happens, it's the same as not finding any lines. Don't need to special case.
* Use of utility functions is mostly for generic-mapping
* (avoiding annoying double-type-casting plus editor warnings)
*/
CompletableFuture<Optional<Long>> run1() {
return
CompletableFuture.supplyAsync(() -> openFile(fileName))
.thenApplyAsync(c -> { // this stage MUST close the prior stage
if(cancelled.isCancelled() || c == null) return Util.emptyString(); // shouldn't throw
try {
return c
.lines()
.filter(line -> !cancelled.isCancelled())
.filter(line -> !line.startsWith("#"))
.findFirst();
} catch (RuntimeException e) {
Util.closeQuietly(c);
throw new RuntimeException(e);
}
}
)
.thenApplyAsync(oLine -> // this stage doesn't need closing
oLine
.map(line -> line.split(":"))
.map(cols -> cols[2])
.map(Long::valueOf)
)
;
}
/**
* Same as run1 but avoids messy brackets + try-finally
*/
CompletableFuture<Optional<Long>> run2() {
return
CompletableFuture.supplyAsync(() -> openFile(fileName))
.thenApplyAsync(c -> // this stage MUST close the prior stage
Util.runThenCloseQuietly(
c
, r -> cancelled.isCancelled() ? Util.emptyString() // shouldn't throw
: r
.lines()
.filter(line -> !cancelled.isCancelled())
.filter(line -> !line.startsWith("#"))
.findFirst()
))
.thenApplyAsync(oLine -> // this stage doesn't need closing
oLine
.map(line -> line.split(":"))
.map(cols -> cols[2])
.map(Long::valueOf)
)
;
}
/**
* Same as run2 but avoids needing the teneary operator - says Cancellable in func-name so is more readable
*/
CompletableFuture<Optional<Long>> run3() {
return
CompletableFuture.supplyAsync(() -> openFile(fileName))
.thenApplyAsync(c -> // this stage MUST close the prior stage
Util.runThenCloseQuietlyCancellable(
cancelled::isCancelled // lambda here is slightly easier to read than explicit if-statement
, c
, r -> r
.lines()
.filter(line -> !cancelled.isCancelled())
.filter(line -> !line.startsWith("#"))
.findFirst()
))
.thenApplyAsync(oLine -> // this stage doesn't need closing
oLine
.map(line -> line.split(":"))
.map(cols -> cols[2])
.map(Long::valueOf)
)
;
}
}
#Test
public void testFooGood() {
var task = new FooTask("/etc/passwd");
var cf = task.run3();
var oVal = cf.join();
assertTrue(oVal.isPresent());
System.out.println(oVal.get()); // should not throw
}
#Test
public void testFooCancel() {
var task = new FooTask("/etc/passwd");
var cf = task.run3();
task.cancel();
var oVal = cf.join();
assertTrue(oVal.isEmpty());
}

Related

Stopping a thread in java CompletableFuture after timeout

I have an async chain in my java code that i want to stop after a certain timeout
so i created a threadPool with some threads and called the CompletableFuture like this
ExecutorService pool = Executors.newFixedThreadPool(10);
than i have a cyclic method that loads data from the db and executes some task on it, once all the CompletableFutures are completed its doing it again
CompletableFuture<MyObject> futureTask =
CompletableFuture.supplyAsync(() -> candidate, pool)
.thenApply(Task1::doWork).thenApply(Task2::doWork).thenApply(Task3::doWork)
.thenApply(Task4::doWork).thenApply(Task5::doWork).orTimeout(30,TimeUnit.SECONDS)
.thenApply(Task6::doWork).orTimeout(30,TimeUnit.SECONDS)
.exceptionally(ExceptionHandlerService::handle);
My problem is in task6, that has a very intensive task (its a network connection task that sometimes hangs forever)
i noticed that my orTimeout is being fired correctly after 30 seconds, but the thread running Task6 is still being running
after few cycles like this, all my threads are drained and my app dies
How can i cancel the running threads on the pool after the timeout has reached?
(without calling pool.shutdown())
UPDATE*
inside the main thread i did a simple check as shown here
for (int i = TIME_OUT_SECONDS; i >= 0; i--) {
unfinishedTasks = handleFutureTasks(unfinishedTasks, totalBatchSize);
if(unfinishedTasks.isEmpty()) {
break;
}
if(i==0) {
//handle cancelation of the tasks
for(CompletableFuture<ComplianceCandidate> task: unfinishedTasks) {
**task.cancel(true);**
log.error("Reached timeout on task, is canceled: {}", task.isCancelled());
}
break;
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception ex) {
}
}
What i see is that after few cycles, all the tasks complain about timeout...
in the first 1-2 cycles, i still get epected responses (while there are threads to process it)
i still feel that the thread pool is exhausted
I know you said without calling pool.shutDown, but there is simply no other way. When you look at your stages though, they will run in either the thread that "appends" them (adding those thenApply) or a thread from that pool that you define. May be an example should make more sense.
public class SO64743332 {
static ExecutorService pool = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> dbCall(), pool);
//simulateWork(4);
CompletableFuture<String> f2 = f1.thenApply(x -> {
System.out.println(Thread.currentThread().getName());
return transformationOne(x);
});
CompletableFuture<String> f3 = f2.thenApply(x -> {
System.out.println(Thread.currentThread().getName());
return transformationTwo(x);
});
f3.join();
}
private static String dbCall() {
simulateWork(2);
return "a";
}
private static String transformationOne(String input) {
return input + "b";
}
private static String transformationTwo(String input) {
return input + "b";
}
private static void simulateWork(int seconds) {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
} catch (InterruptedException e) {
System.out.println("Interrupted!");
e.printStackTrace();
}
}
}
They key point of the above code is this : simulateWork(4);. Run the code with it commented out and then uncomment it. See what thread is actually going to execute all those thenApply. It is either main or the same thread from the pool, meaning although you have a pool defined - it's only a single thread from that pool that will execute all those stages.
In this context, you could define a single thread executor (inside a method let's say) that will run all those stages. This way you could control when to call shutDownNow and potentially interrupt (if your code responds to interrupts) the running task. Here is a made-up example that simulates that:
public class SO64743332 {
public static void main(String[] args) {
execute();
}
public static void execute() {
ExecutorService pool = Executors.newSingleThreadExecutor();
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> dbCall(), pool);
CompletableFuture<String> cf2 = cf1.thenApply(x -> transformationOne(x));
// give enough time for transformationOne to start, but not finish
simulateWork(2);
try {
CompletableFuture<String> cf3 = cf2.thenApply(x -> transformationTwo(x))
.orTimeout(4, TimeUnit.SECONDS);
cf3.get(10, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
pool.shutdownNow();
}
}
private static String dbCall() {
System.out.println("Started DB call");
simulateWork(1);
System.out.println("Done with DB call");
return "a";
}
private static String transformationOne(String input) {
System.out.println("Started work");
simulateWork(10);
System.out.println("Done work");
return input + "b";
}
private static String transformationTwo(String input) {
System.out.println("Started transformation two");
return input + "b";
}
private static void simulateWork(int seconds) {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
} catch (InterruptedException e) {
System.out.println("Interrupted!");
e.printStackTrace();
}
}
}
Running this you should notice that transformationOne starts, but it is interrupted because of the shutDownNow.
The drawback of this should be obvious, every invocation of execute will create a new thread pool...

Detecting a timeout exception on a Java Future without calling get() on it

I am building a library that needs to some bluetooth operations on Android. I want to return a Future instance, so whoever is using my library can call .get() on the future returned and can handle ExecutionException, TimeoutException and InterruptedException themselves. However, I want to detect a timeout myself because I need to some cleanup logic like disconnecting from the device and so on. How can I achieve this?
You could implement a wrapper class around Future which delegates to a different one (the one returned by wherever you're getting your Future at the moment). Something like:
final class DelegatingFuture<T> implements Future<T> {
private final Future<T> delegate;
DelegatingFuture(final Future<T> delegate) {
this.delegate = Objects.requireNonNull(delegate);
}
// All other methods simply delegate to 'delegate'
#Override
public T get()
throws InterruptedException, ExecutionException {
try {
return this.delegate.get();
} catch (final Exception ex) {
// Handle cleanup...
throw ex;
}
}
// Something similar for get(long timeout, TimeUnit unit)
}
And then simply return new DelegatingFuture<>(currentFuture); wherever your handing these out.
The timeout is relevant to the caller of the get method with timeout and only to that caller. A timeout is nowhere meant to imply a cancellation. E.g., the following code is a legitimate usage of the Future API:
ExecutorService es = Executors.newSingleThreadExecutor();
Future<String> f = es.submit(() -> {
Thread.sleep(3000);
return "hello";
});
for(;;) try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
break;
}
catch(TimeoutException ex) {
// perhaps, do some other work
System.out.println("will wait something more");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
break;
}
es.shutdown();
Tying the cleanup to the methods actually intended to query the result, is not a useful approach. The timeout provided by the caller(s) of that method do not relate to the actual operation. There’s not even a guaranty that the result will be queried before the operations ends or that it gets queried at all.
The cleanup should happen when either, the operation finished or when the future gets cancelled explicitly. If the caller intends a cancellation after a timeout, the caller only needs to invoke cancel after catching a TimeoutException.
One approach, often pointed to, is to use a CompletionService, e.g.
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
static final CompletionService<String> COMPLETION_SERVICE
= new ExecutorCompletionService<>(MY__EXECUTOR);
static final Future<?> CLEANER = MY__EXECUTOR.submit(() -> {
for(;;) try {
Future<String> completed = COMPLETION_SERVICE.take();
System.out.println("cleanup "+completed);
} catch(InterruptedException ex) {
if(MY__EXECUTOR.isShutdown()) break;
}
});
public static Future<String> doSomeWork() {
return COMPLETION_SERVICE.submit(() -> {
Thread.sleep(3000);
return "hello";
});
}
You are in control over when to poll the completed futures, like in another background thread, as shown in the example, or right before commencing new jobs.
You can test it like
Future<String> f = doSomeWork();
try {
String s = f.get(500, TimeUnit.MILLISECONDS);
System.out.println("got "+s);
}
catch(TimeoutException ex) {
System.out.println("no result after 500ms");
}
catch (ExecutionException ex) {
System.out.println("failed with "+ex);
}
if(f.cancel(true)) System.out.println("canceled");
f = doSomeWork();
// never calling get() at all
But honestly, I never understood why such complicated things are actually necessary. If you want a cleanup at the right time, you can use
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
FutureTask<String> ft = new FutureTask<>(actualJob) {
#Override
protected void done() {
System.out.println("cleanup "+this);
}
};
MY__EXECUTOR.execute(ft);
return ft;
}
to achieve the same.
Or even simpler
static final ExecutorService MY__EXECUTOR = Executors.newCachedThreadPool();
public static Future<String> doSomeWork() {
Callable<String> actualJob = () -> {
Thread.sleep(3000);
return "hello";
};
return MY__EXECUTOR.submit(() -> {
try {
return actualJob.call();
}
finally {
// perform cleanup
System.out.println("cleanup");
}
});
}
In either case, the cleanup will be performed whether the job was completed successfully, failed, or got canceled. If cancel(true) was used and the actual job supports interruption, the cleanup also will be performed immediately after.

Resubmitting/scheduling task from the task itself - is it a good practice?

Consider we have a scheduled executor service:
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(...);
And for some logic we want to retry a task execution. The following approach seems to be smelling for me, but I can't understand why:
threadPool.submit(new Runnable() {
#Override
public void run() {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
}
});
The one obvious problem I see is that this code is not possible to convert to lambda:
threadPool.submit(()-> {
// ...
if (needToBeScheduled()) {
threadPool.schedule(this, delay, TimeUnit.MINUTES);
} else if (needToBeResubmitted()) {
threadPool.submit(this);
}
});
^^ this won't compile, as we can not refer this from lambda. Though it can be solved by introducing a method which produces such an instance and provide it instead of this.
But this is only one disadvantage I see. Is anything else here which can cause any problems? Perhaps there is a more proper approach? Move this logic to ThreadPoolExecutor.afterExecute() (this causes type conversion though...)?
Assuming that object is stateless, i.e. there are no object variables in Runnable instance.
P.S. The logic of what to do (reschedule task or resubmit or do nothing) is based on some information retrieved from the database (or any external source). So Runnable is still stateless, but it calculates the outcome based on some results of its work.
Honestly, I don't like the approach where a task (a simple independent unit of work) decides whether it should put itself in the service or not and interacts with the ExecutorService directly. I believe // ... is the only part a task should execute.
I would convert a Runnable in a Callable<Boolean>:
Callable<Boolean> task = () -> {
// ...
return needToBeScheduled; // or sth more complex with several boolean fields
};
And I would definitely move that logic outside a task (for example, into a service method):
Future<Boolean> future = threadPool.submit(task);
try {
boolean needToBeScheduled = future.get();
if (needToBeScheduled) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
By something more complex I meant a class that comprises 2 boolean fields. It takes Supplier<Boolean>s to make things lazy.
final class TaskResult {
private final Supplier<Boolean> needToBeScheduled;
private final Supplier<Boolean> needToBeResubmitted;
private TaskResult(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
this.needToBeScheduled = needToBeScheduled;
this.needToBeResubmitted = needToBeResubmitted;
}
public static TaskResult of(Supplier<Boolean> needToBeScheduled, Supplier<Boolean> needToBeResubmitted) {
return new TaskResult(needToBeScheduled, needToBeResubmitted);
}
public boolean needToBeScheduled() {
return needToBeScheduled != null && needToBeScheduled.get();
}
public boolean needToBeResubmitted() {
return needToBeResubmitted != null && needToBeResubmitted.get();
}
}
With a few changes to the above example, we have:
Callable<TaskResult> task = () -> {
// ...
return TaskResult.of(() -> needToBeScheduled(), () -> needToBeResubmitted());
};
final Future<TaskResult> future = threadPool.submit(task);
try {
final TaskResult result = future.get();
if (result.needToBeScheduled()) {
threadPool.schedule(task, delay, TimeUnit.MINUTES);
}
if (result.needToBeResubmitted()) {
threadPool.submit(task);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

Producer consumer in batches; second batch shouldn't come until the previous batch is complete

I'm trying to implement a mechanism where the runnables are both producer and consumer;
Situation is-
I need to read records from the DB in batches, and process the same. I'm trying this using producer consumer pattern. I get a batch, I process. Get a batch, process. This gets a batch whenever it sees queue is empty. One of the thread goes and fetches things. But the problem is that I can't mark the records that get fetched for processing, and that's my limitation. So, if we fetch the next batch before entirely committing the previous, I might fetch the same records again. Therefore, I need to be able to submit the previous one entirely before pulling the other one. I'm getting confused as to what should I do here. I've tried keeping the count of the fetched one, and then holding my get until that count is reached too.
What's the best way of handling this situation? Processing records from DB in chunks- the biggest limitation I've here is that I can't mark the records which have been picked up. So, I want batches to go through sequentially. But a batch should use multithreading internally.
public class DealStoreEnricher extends AsyncExecutionSupport {
private static final int BATCH_SIZE = 5000;
private static final Log log = LogFactory.getLog(DealStoreEnricher.class);
private final DealEnricher dealEnricher;
private int concurrency = 10;
private final BlockingQueue<QueryDealRecord> dealsToBeEnrichedQueue;
private final BlockingQueue<QueryDealRecord> dealsEnrichedQueue;
private DealStore dealStore;
private ExtractorProcess extractorProcess;
ExecutorService executor;
public DealStoreEnricher(DealEnricher dealEnricher, DealStore dealStore, ExtractorProcess extractorProcess) {
this.dealEnricher = dealEnricher;
this.dealStore = dealStore;
this.extractorProcess = extractorProcess;
dealsToBeEnrichedQueue = new LinkedBlockingQueue<QueryDealRecord>();
dealsEnrichedQueue = new LinkedBlockingQueue<QueryDealRecord>(BATCH_SIZE * 3);
}
public ExtractorProcess getExtractorProcess() {
return extractorProcess;
}
public DealEnricher getDealEnricher() {
return dealEnricher;
}
public int getConcurrency() {
return concurrency;
}
public void setConcurrency(int concurrency) {
this.concurrency = concurrency;
}
public DealStore getDealStore() {
return dealStore;
}
public DealStoreEnricher withConcurrency(int concurrency) {
setConcurrency(concurrency);
return this;
}
#Override
public void start() {
super.start();
executor = Executors.newFixedThreadPool(getConcurrency());
for (int i = 0; i < getConcurrency(); i++)
executor.submit(new Runnable() {
public void run() {
try {
QueryDealRecord record = null;
while ((record = get()) != null && !isCancelled()) {
try {
update(getDealEnricher().enrich(record));
processed.incrementAndGet();
} catch (Exception e) {
failures.incrementAndGet();
log.error("Failed to process deal: " + record.getTradeId(), e);
}
}
} catch (InterruptedException e) {
setCancelled();
}
}
});
executor.shutdown();
}
protected void update(QueryDealRecord enrichedRecord) {
dealsEnrichedQueue.add(enrichedRecord);
if (batchComplete()) {
List<QueryDealRecord> enrichedRecordsBatch = new ArrayList<QueryDealRecord>();
synchronized (this) {
dealsEnrichedQueue.drainTo(enrichedRecordsBatch);
}
if (!enrichedRecordsBatch.isEmpty())
updateTheDatabase(enrichedRecordsBatch);
}
}
private void updateTheDatabase(List<QueryDealRecord> enrichedRecordsBatch) {
getDealStore().insertEnrichedData(enrichedRecordsBatch, getExtractorProcess());
}
/**
* #return true if processed records have reached the batch size or there's
* nothing to be processed now.
*/
private boolean batchComplete() {
return dealsEnrichedQueue.size() >= BATCH_SIZE || dealsToBeEnrichedQueue.isEmpty();
}
/**
* Gets an item from the queue of things to be enriched
*
* #return {#linkplain QueryDealRecord} to be enriched
* #throws InterruptedException
*/
protected synchronized QueryDealRecord get() throws InterruptedException {
try {
if (!dealsToBeEnrichedQueue.isEmpty()) {
return dealsToBeEnrichedQueue.take();
} else {
List<QueryDealRecord> records = getNextBatchToBeProcessed();
if (!records.isEmpty()) {
dealsToBeEnrichedQueue.addAll(records);
return dealsToBeEnrichedQueue.take();
}
}
} catch (InterruptedException ie) {
throw new UnRecoverableException("Unable to retrieve QueryDealRecord", ie);
}
return null;
}
private List<QueryDealRecord> getNextBatchToBeProcessed() {
List<QueryDealRecord> recordsThatNeedEnriching = getDealStore().getTheRecordsThatNeedEnriching(getExtractorProcess());
return recordsThatNeedEnriching;
}
#Override
public void stop() {
super.stop();
if (executor != null)
executor.shutdownNow();
}
#Override
public boolean await() throws InterruptedException {
return executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS) && !isCancelled() && complete();
}
#Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return executor.awaitTermination(timeout, unit) && !isCancelled() && complete();
}
private boolean complete() {
setCompleted();
return true;
}
}
You're already using a BlockingQueue - it does all that work for you.
However, you're using the wrong method addAll() to add new elements to the queue. That method will throw an exception if the queue is not able to accept elements. Rather you should use put() because that's the blocking method corresponding to take(), which you are using correctly.
Regarding your statement in the post title:
second batch shouldn't come until the previous batch is complete
You need not be concerned about the timing of the incoming versus outgoing batches if you use BlockingQueue correctly.
It looks like a Semaphore will work perfectly for you. Have the producing thread acquire the semaphore while the consuming thread releases the semaphore when it completes the batch.
BlockingQueue blockingQueue = ...;
Semapore semaphore = new Semaphore(1);
Producing-Thread
Batch batch = db.getBatch();
semaphore.acquire(); // wait until previous batch completes
blockingQueue.add(batch);
Consuming Thread
for(;;){
Batch batch = blockingQueue.take();
doBatchUpdate(batch);
semaphore.release(); // tell next batch to run
}

Catching thread exceptions from Java ExecutorService

I'm working on a software development framework for parallel computing JavaSeis.org. I need a robust mechanism for reporting thread exceptions. During development, knowing where exceptions came from has high value, so I would like to err on the side of over-reporting. I would also like to be able to handle Junit4 testing in threads as well. Is the approach below reasonable or is there a better way ?
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThreadFailure {
public static void main(String[] args) {
int size = 1;
ExecutorService exec = Executors.newFixedThreadPool(size);
ThreadFailTask worker = new ThreadFailTask();
Future<Integer> result = exec.submit(worker);
try {
Integer value = result.get();
System.out.println("Result: " + value);
} catch (Throwable t) {
System.out.println("Caught failure: " + t.toString());
exec.shutdownNow();
System.out.println("Stack Trace:");
t.printStackTrace();
return;
}
throw new RuntimeException("Did not catch failure !!");
}
public static class ThreadFailTask implements Callable<Integer> {
#Override
public Integer call() {
int nbuf = 65536;
double[][] buf = new double[nbuf][nbuf];
return new Integer((int) buf[0][0]);
}
}
}
Consider calling execute() instead of submit() on the ExecutorService. A Thread invoked with execute() will invoke the Thread.UncaughtExceptionHandler when it fails.
Simply make a ThreadFactory that installs a Thread.UncaughtExceptionHandler on all Threads and then invoke your work with execute() on the ExecutorService instead of submit().
Have a look at this related stack overflow question.
I don't believe there is a standard 'hook' to get to these exceptions when using submit(). However, if you need to support submit() (which sounds reasonable, given that you use a Callable), you can always wrap the Callables and Runnables :
ExecutorService executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()) {
#Override
public <T> Future<T> submit(final Callable<T> task) {
Callable<T> wrappedTask = new Callable<T>() {
#Override
public T call() throws Exception {
try {
return task.call();
}
catch (Exception e) {
System.out.println("Oh boy, something broke!");
e.printStackTrace();
throw e;
}
}
};
return super.submit(wrappedTask);
}
};
Of course, this method only works if you're the one building the ExecutorService in the first place. Furthermore, remember to override all three submit() variants.
As explained in this thread What is the difference between submit and execute method with ThreadPoolExecutor, using execute will only work if you implement Runnable and not Callable as execute cannot return a Future.
I think in your scenario you should build the future object so that it can accommodate the exception stuff also. So in case of exception you build the error message object.
My original question asked how to implement "robust" thread exception handling with Java ExecutorService. Thanks to Angelo and Greg for pointers on how exception handling works with ExecutorService.submit() and Future.get(). My revised code fragment is shown below. The key point I learned here is that Future.get() catches all exceptions. If the the thread was interrupted or cancelled, you get the appropriate exception, otherwise, the exception is wrapped and re-thrown as an ExecutionException.
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThreadFailure {
public static void main(String[] args) {
int size = 1;
ExecutorService exec = Executors.newFixedThreadPool(size);
ThreadFailTask worker = new ThreadFailTask();
Future result = exec.submit(worker);
try {
Integer value = result.get();
System.out.println("Result: " + value);
} catch (ExecutionException ex) {
System.out.println("Caught failure: " + ex.toString());
exec.shutdownNow();
return;
} catch (InterruptedException iex) {
System.out.println("Thread interrupted: " + iex.toString());
} catch (CancellationException cex) {
System.out.println("Thread cancelled: " + cex.toString());
}
exec.shutdownNow();
throw new RuntimeException("Did not catch failure !!");
}
public static class ThreadFailTask implements Callable {
#Override
public Integer call() {
int nbuf = 65536;
double[][] buf = new double[nbuf][nbuf];
return new Integer((int) buf[0][0]);
}
}
}
I didn't have a great deal of luck with other answers because I needed the actual exception instance, itself, not just a printed stack trace. For me, the accepted answer involving ThreadPoolExecutor#afterExecute() of the question "Why is UncaughtExceptionHandler not called by ExecutorService?" worked.
See the following sample code:
List<Runnable> tasks = new LinkedList<>();
for (int i = 0; i < numThreads; ++i) {
Runnable task = new Runnable() {
#Override
public void run() {
throw new RuntimeException();
}
};
tasks.add(task);
}
Optional<Throwable> opEmpty = Optional.empty();
/*
* Use AtomicReference as a means of capturing the first thrown exception, since a
* spawned thread can't "throw" an exception to the parent thread.
*/
final AtomicReference<Optional<Throwable>> firstThrownException =
new AtomicReference<>(opEmpty);
/*
* Use new ThreadPoolExecutor instead of Executors.newFixedThreadPool() so
* that I can override afterExecute() for the purposes of throwing an
* exception from the test thread if a child thread fails.
*/
ExecutorService execSvc = new ThreadPoolExecutor(numThreads, numThreads,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
#Override
public void afterExecute(Runnable task, Throwable failureCause) {
if(failureCause == null) {
// The Runnable completed successfully.
return;
}
// only sets the first exception because it will only be empty on the first call.
firstThrownException.compareAndSet(Optional.<Throwable>empty(), Optional.of(failureCause));
}
};
for (Runnable task : tasks) {
execSvc.execute(task);
}
execSvc.shutdown();
execSvc.awaitTermination(1, TimeUnit.HOURS);
assertEquals(firstThrownException.get(), Optional.empty());
To Handling exceptions in ExecutorService you have to take the advantage of Callable and Future.
Callable is similar to Runnable and both are functional interface but run() of Runnable doesn't throws exception and the return type is void where as call() of Callable returns a generics and throws exception.
Java-8 way:
ExecuterService executor = null;
Future<Integer> future = null;
Callable<Integer> yourTask = () -> {
//your implementation here();
//your implementation here();
};
try
{
executor = Executors.newCachedThreadPool();
future = executor.submit(yourTask );
Integer result = future.get();
System.out.println(result);
}
catch (ExecutionException | TimeoutException | InterruptedException e)
{
// TODO: handle exception
}
finally
{
executer.shutdown();
}

Categories

Resources