Let's say I have this Java code that does something asynchronously:
public String main() {
try {
// Code before that could throw Exceptions
CompletableFuture.runAsync(() -> {...});
// Code after that could throw Exceptions
} catch (SomeException e) {
// ...
} catch (CompletionException e) {
// ...
}
}
If this were to run and the Async task successfully starts executing, will it still complete even if something else throws an Exception? If not, how can I let the async call finish executing while the Exception gets thrown?
If this were to run and the Async task successfully starts executing, will it still complete even if something else throws an Exception?
yes. The task is not interrupted.
NOTE: If your program exits as a result of an Exception, then the task will be stopped.
If not, how can I let the async call finish executing while the Exception gets thrown?
It does this by default.
If you want to cancel the task however it might ignore the interrupt.
public String main() {
CompletableFuture future = null;
try {
// Code before that could throw Exceptions
future = CompletableFuture.runAsync(() -> {...});
// Code after that could throw Exceptions
} catch (SomeException e) {
if (future != null) future.cancel(true);
// ...
} catch (CompletionException e) {
// ...
}
}
As long as the task has already started, any exceptions thrown after the call to runAsync will not affect that task.
Exceptions propagate up the call stack. A call stack is local to a particular thread. As your task is running asynchronously (i.e. on another thread), there is no way for an exception thrown on another thread to affect it.
Related
Here is my parser class:
public class InputFilesParser {
private ExecutorService executorService;
private volatile Throwable thrownError;
public InputFilesParser(int poolSize) {
this.executorService = Executors.newFixedThreadPool(poolSize, (r) -> {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((thread, e) -> {
//this should be called before the thread has finished.
this.notifyOnException(thread, e);
});
return t;
});
}
}
public void parseFile(Path inputFilePath) throws Throwable {
//if exception is set, then no more files will be processed.
if (this.thrownError != null) {
//execution will stop here because an error will be thrown from waitToFinish()
this.waitToFinish();
}
this.executorService.execute(() -> {
//this will always throw an exception which have to be handled by the above mentioned uncaughtExceptionHandler.
this.processFile(inputFilePath);
});
}
private void processFile(Path inputFilePath) {
throw new RuntimeExecption();
}
public void waitToFinish() throws Throwable {
this.executorService.shutdown();
while (true) {
try {
//if statement will be entered only when awaitTermination returns true, meaning all the tasks are finished.
if (this.executorService.awaitTermination(STOP_CHECK_TIMEOUT, TimeUnit.SECONDS)) {
synchronized (this) {
//in this scenario, after all tasks are finished, the thrownError should be set
if (this.thrownError != null) {
//I expect to get this output
System.out.println("Exception: " + this.thrownError);
throw this.thrownError;
}
//but I get this output
System.out.println("No exception: " + this.thrownError);
}
break;
}
} catch (InterruptedException e) {
LOG.info("An interruption occurred", e);
}
}
}
private synchronized void notifyOnException(Thread thread, Throwable t) {
//if the thrownError isn't set, then set it here so that waitToFinish() will know that an error occurred.
if (this.thrownError == null) {
this.thrownError = t;
}
}
}
on the calling thread, I have the following:
InputFilesParser ifp = new InputFilesParser(poolSize);
try {
for (Path f : files) {
//each parsing will throw an exception in this scenario
ifp.parseFile(f);
}
//an exception should be detected and the error thrown, but actually this is not happening, but printing No exception... message.
ifp.waitToFinish();
catch(Exception e) {
e.printStackTrace();
}
Although there is an exception thrown, the calling thread gets in waitToFinish() method, printing null for the thrown exception:
Thread: Thread-5. No exception: null
This means that awaitTermination returns true, before the exception is set in notifyOnException method. But notifyOnException method is called from a thread run by this executor service. In my opinion there is a problem with my understanding, or there is a problem with java.
Any idea which one of this :) ? In my opinion, this shouldn't be possible. Am I missing something about setUncaughtExceptionHandler method and the way how it handles the exceptions? Although from documentation it seems that this method is called by the thread throwing the exception.
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
Set the handler invoked when this thread abruptly terminates due to an uncaught exception.
A thread can take full control of how it responds to uncaught exceptions by having its uncaught exception handler explicitly set. If no such handler is set then the thread's ThreadGroup object acts as its handler.
Parameters:
eh - the object to use as this thread's uncaught exception handler. If null then this thread has no explicit handler.
Thanks in advance.
It seems to me that my assumption in regard to UncaughtExceptionHanlder's method call is wrong.
Java docs says this:
public static interface Thread.UncaughtExceptionHandler
Interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.
When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using Thread.getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments.
With other words, it is not the thread itself which calls the UncaughtExceptionHandler's method, but JVM. This means that there is no constraint in regard to the order of operations when awaitTermination is called.
I'm working on a program that processing a large stream of items and sends each result to a REST server. That server has a rate limit of 2000 requests per hour, so the program must pause a while between processing two items. Items failed to process should be presented to the user afterwards.
It all worked fine, until I discovered that shutdownNow() isn't working when the program is closed. The UI closes but the executor keeps working. Underneath a brief summary of the code.
ExecutorService exec = Executors.newSingleThreadExecutor();
SomeProcessor p = new SomeProcessor();
void process() {
exec.submit(() -> {
Stream<SomeObject> s = ...
List<SomeObject> failed = p.process(s);
// show failed in UI
};
}
void exit() {
exec.shutdownNow();
}
And the SomeProcessor class:
List<SomeObject> process(Stream<SomeObject> s) {
List<SomeObject> failed = s
.sequential()
.filter(o -> !ignore(o)) // ignore irrelevant items
.peek(o -> pause()) // make sure not to exceed server's rate limit
.filter(o -> !process(o)) // keep items failed to process
.collect(Collectors.asList());
return failed;
}
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
Thread.interrupted();
}
}
boolean process(SomeObject o) {
if (Thread.interrupted()) // make task interruptible
// *** but then what? ***
try {
// process o and send result to server
return true;
} catch (SomeException e) {
return false;
}
}
I guess that shutdownNow() wasn't working because the task isn't interruptible. So I'm trying to make the task interruptible, but I don't know what it should look like. Any ideas?
And a bonus question too. The pause() method does what it should do. Still I'd rather use something like ScheduledThreadPoolExecutor.scheduleAtFixedRate(.), but then processing a stream of tasks. Does anything exist like that?
Thanks for any help!
Look at your pause method:
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
Thread.interrupted();
}
}
You are already detecting interruption at this point but react on it by setting the interrupt state of the thread again, or at least trying to do so, as Thread.interrupted() should be Thread.currentThread().interrupt() to achieve this, which would be fine, if you do not want to support interruption, but here it is counter-productive. It will cause your next sleep call to throw an InterruptedException immediately, which you handle the same way, and so on. As a result, you’re not only proceeding with the processing of the remaining elements, you’re doing it without the sleeping between the elements.
When you change the method to
void pause() {
try {
TimeUnit.MILLISECONDS.sleep(...);
} catch (final InterruptedException e) {
throw new IllegalStateException("interrupted");
}
}
interruption will terminate your stream operation with the IllegalStateException. For clarity, you may define your own exception type (extending RuntimeException) for this scenario, distinguishable from all other exception types.
I want to interrupt a sleeping thread, but it throws InterruptedException and doesn't stop. When I put Thread.interrupt() to the catch block, it interrupts the thread, but not from the first try.
I have a message, which must be written to file, when the thread is interrupted, but it write this message about 4-5 times. So I understand that thread is not interrupted at once. Why is it so, and what do I have to do?
My code has variable count of threads which changes at run-time. Each thread call method printAndDelay, which makes record to file and sleep. But I must have opportunity to stop any thread in any moment from main thread and record reason of stop to the same file.
void printAndDelay(String message, int delay)
{
try {
writeToLogFile(message, logFileName);
Thread.sleep(delay);
}
catch (InterruptedException e)
{
writeToLogFile("The reason of cancelling", logFileName);
Thread.currentThread().interrupt();
}
}
I try to interrupt thread by this code:
void stopOrder(String threadName)
{
Map<Thread, StackTraceElement[]> threads = Thread.getAllStackTraces();
threads.keySet().stream()
.filter(k -> k.getName().equalsIgnoreCase(threadName))
.findFirst()
.get()
.interrupt();
}
and I see that I can find this thread, but it throws InterruptException but doesn't stop thread. So I tried to stop it by putting Thread.interrupt() into the catch block.
For the message to be printed 4-5 times, you presumably have some loop which is calling printAndDelay multiple times:
for (Object obj : someList)
{
printAndDelay("hello", 1000);
}
Rather than dealing with the exception within printAndDelay, declare it as thrown in the method signature and deal with it from where the method is called.
void printAndDelay(String message, int delay) throws InterruptedException
{
writeToLogFile(message, logFileName);
Thread.sleep(delay);
}
You would alter your loop like so:
try
{
for (Object obj : someList)
{
printAndDelay("hello", 1000);
}
}
catch (final InterruptedException e)
{
writeToLogFile("The reason of cancelling", logFileName);
}
If "the reason of cancelling" is not a constant, you may want to wrap the InterruptedException in some other exception type, possibly a custom one, to pass the message upwards.
You need to do it like this. Stop the execution of the thread by throwing the InterruptedException.
void printAndDelay(String message, int delay) throws InterruptedException {
try {
writeToLogFile(message, logFileName);
Thread.sleep(delay);
} catch (InterruptedException e) {
writeToLogFile("The reason of cancelling", logFileName);
// propagate the exception
throw e;
}
}
And in the run method you need to restore the interrupt status.
public void run() {
try {
// whatever you want to do
printAndDelay(.....
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
The reason why I throw the InterruptedException and don't wrap it in another exception is that I want to restore the interrupt of the thread in the run method. You can even restore the interrupt right in the method and then throw some custom exception or a RuntimeException and stop the execution of your thread.
As is known ThreadPoolExecutor have 2 methods to push tasks:
submit and execute.
As I understand - main difference the following:
Submit returns Future and if we can observe exeption occured in task after call
future.get();
But if exception occures in task pushed as submit - we will see this exception in console(surely if this exception will not explicitly catch)
I tried to investigate ThreadPoolExecutor code and find how this was implemented.
The thing I noticed, submit method uses execute method inside:
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
But I cannot find place in code where detects should we swallow exception - or not.
Please help to find this logic in code.
Your taskis a a FutureTask.
If you look at the source code (grepcode) of the run method :
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
You see that all Throwable are swallowed here.
Suppose I have a method as follows:
public void poll(Callable<Boolean> callable) {
ScheduledExecutorService service = Executors.newSingleThreadedScheduledExecutor();
Future<Boolean> future = service.schedule(callable, 0L, TimeUnit.MILLISECONDS);
try {
while (!future.get()) {
future = service.schedule(callable, 5L, TimeUnit.MINUTES);
}
} catch (ExecutionException e) {
// ...
} catch (InterruptedException e) {
// ...
} finally {
service.shutdown();
}
}
How does an InterruptedException ever get thrown (and caught in poll())? Anything thrown by the callable (including InterruptedException, right?) would be an ExecutionException, we never cancel any futures, and the service's shutdownNow() is never called.
Aside: being what it is, is it possible to make this polling method more bulletproof against things like InterruptedException?
The InterruptedException would be thrown by get while waiting (blocking) for the callable to finish.
I'm not sure what you mean by bulletproof, you have to handle the possibility of the exception being thrown.
InterruptedException can be thrown by the thread which called get and is waiting for completion, not by the callable