2

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!

0

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, this sounds like a good idea, so I'm guessing you were thinking about something like this in a main loop: while (!isFinished(future)) { // do some other stuff... } and check if future already finished: private static boolean isFinished(Future<?> future) { try { future.get(1, SECONDS); return true; } catch (TimeoutException e) { return false; } catch (ExecutionException e) { throw new RuntimeException(e); } } Thanks for the suggestion!
There is an 'isDone' method on the future that can be used to check if the future is ready. I'm not sure if checking the isDone in some loop is the best approach; it will depend on the situation.
Or use CompletableFuture<?> future = CompletableFuture.runAsync(() -> { /* your operation */ }, yourExecutor);, then, you can not only use isDone() to check for completion in general, but also, e.g. if(future.isCompletedExceptionally()) future.join(); to re-throw.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.