Im familiar with the fact that we as developers need to add a check for interrupts in our code when we write something that might run async via threads.
The following example shows the wrong case, when there is no check for interrupt in the runnable and therefore even if I got timeout exception on the main thread, the child thread keep running the task :
public void myTest() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Void> future = executorService.submit(() -> {
while (true) {
log.info("test");
Thread.sleep(40);
}
});
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
Thread.sleep(500);
log.info("done");
output :
test
test
test
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at myFile.myTest(MyFile.java:102)
test
test
test
test
done
By adding future.cancel(true) I got an unexpected behavior. According to what I understood, the cancel(boolean) method wont stop the task, if the task is already running, it might only interrupt it and thats all.
The code :
public void myTest() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Void> future = executorService.submit(() -> {
while (true) {
log.info("test");
Thread.sleep(40);
}
});
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
boolean value = future.cancel(true);
log.info(""+value);
}
Thread.sleep(500);
log.info("done");
The output :
test
test
test
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at myFile.myTest(MyFile.java:102)
true
done
So why by adding the future.cancel(true) the runnable stopped running ? I expected that during the 500 mili seconds that the main thread sleeps, I will see more test prints like I saw in the previous example.
When you call future.cancel(true), it will try to interrupt your executor thread. Executor thread will receive InterruptedException and die. That's where your FutureTask stops executing.
Related
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.
I have a runnable that I want to run periodically. On a particular run, I believe the runnable encountered a null pointer, but no exception was shown on the console. After that failed run, it never runs again. I have two questions:
If there was a null pointer, why wasn't this shown on the console
How can I have the scheduled task run again in the future, even if a particular run fails?
scheduler = Executors.newScheduledThreadPool(1);
MyRunnable mr = new MyRunnable(this.data);
scheduler.scheduleWithFixedDelay(mr, 0, STATUS_SENDER_PERIOD, TimeUnit.MILLISECONDS);
Answering your questions,
1) The reason why you do not see any kind of exception is due to the fact that the FutureTask#setException called within FutureTask#run effectively swallows it. In order to be be able to log the exception you should either create a new class the extends the ScheduledThreadPoolExecutor and override the afterExecute method like so:
#Override
protected void afterExecute(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
t = e;
}
}
if (t != null) {
t.printStackTrace();
}
}
Or directly invoke get on the returned ScheduledFuture like so:
var executor = Executors.newSingleThreadScheduledExecutor();
var future = executor.scheduleAtFixedRate(new MyRunnable(null), 1, 1, TimeUnit.SECONDS);
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
2) The easiest way of re-running the failed runnable would to do this:
while (true) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
But imho this approach is not the cleanest. Properly coding your Runnable#run method to handle exception would be a better solution.
I want a task to run at scheduled interval and timeout if it does not complete in required time and continue further iteration.
I have gone through the following answers, but it doesn't address my problem..
How do you kill a Thread in Java?
ExecutorService that interrupts tasks after a timeout
Consider the following case
BasicThreadFactory collectionFactory = new BasicThreadFactory.Builder()
.namingPattern("CollectionExecutor-%d")
.build();
// thread pool size is set 2
// 1-for scheduler thread which runs task and tracks timeout
// 2-for task itself
ScheduledExecutorService collectionExecuter =
Executors.newScheduledThreadPool(2, collectionFactory);
// fires collection every minute and if it is in between execution during
// scheduled time then waits for completion and executes immediately
// after it
//my task:
Runnable runnable= new Runnable() {
#Override
public void run() {
try {
System.out.println("Executed started");
Thread.sleep(2000);
System.out.println("Executed after .get method call.");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(20000);
System.out.println("Executed even after .cancel method " +
"call (I want this to avoid this.)");
} catch (Exception e) {
e.printStackTrace();
}
}
};
Above task should run with an interval of 3 sec and stop if it takes more than 1 sec...Consider It is not possible to have complete task in single try catch block, now how could I stop the task to wait further in next sleep(20000) and continue with next iteration.
collectionExecuter.scheduleAtFixedRate(new Runnable() {//scheduler thread
#Override
public void run() {
try {
Future<?> future = collectionExecuter.submit(runnable);
try {
future.get(1, TimeUnit.SECONDS);
} catch (Exception e) {
future.cancel(true);
System.out.println("Collection thread did not " +
"completed in 1 Sec.Thread Interrupted");
}
} catch (Exception e) {
System.out.println("Unable to start Collection Thread");
}
}
}, 0, 3, TimeUnit.SECONDS);
}
I need to execute a Java method for at most X seconds.
In case the method's code does not terminate after X seconds, I need my execution to continue.
I tried to use the following code (using the ExecutorService class).
private void execLoop(){
ExecutorService executor = Executors.newSingleThreadExecutor();
int iteration;
for(iteration=0;iteration<10;iteration++) {
CallableTask ct = new CallableTask();
Future<String> future = executor.submit(ct);
try {
future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
class CallableTask implements Callable {
#Override
public Object call() throws Exception {
Log.d("TIME","executed!");
int t=0;
boolean c = true;
while(c){
t+=0; // infinite loop: this method will never terminate
}
return null;
}
}
What I expect from this code is to print to logcat, every 5 seconds, the string "executed!" for 10 times.
However, the execution gets stuck in the infinite loop.
First, you never shut down your executor. Add the following line as the last statement in your execLoop() method:
executor.shutdownNow();
Then, since the shutdown is accomplished by interrupting your threads, you need to make sure that your CallableTask listens to interrupts. One way is to use Thread.sleep() instead of t+=0:
while(c){
Thread.sleep(500); // This will be interrupted when you call shutdownNow()
}
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.