Why doesn't setting the interrupt bit in a Callable cause the Future that represents the Callable to throw a TimeoutException when Future.get() is called?
public class ExecutorServiceTest extends MockitoTestCase {
private static CountDownLatch latch1 = new CountDownLatch(1);
class TaskChecksForInterruptedExcAndDoesSetInterruptedBit implements Callable<String> {
#Override
public String call() {
latch1.countDown();
while (!Thread.currentThread().isInterrupted()) {
}
Thread.currentThread().interrupt();
return "blah";
}
}
void testInterrupt() throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(numThreads);
Future<String> future = pool.submit(new TaskChecksForInterruptedExcAndDoesSetInterruptedBit());
latch1.await(); // Don't interrupt the Callable until it actually starts processing
pool.shutdownNow();
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (final TimeoutException e) {
// Why doesn't this get called!
return;
}
fail();
}
}
the shutdownNow() call attempts to interrupt all running tasks. In this case the interruption is detected in your busy loop, so the code continues and the Callable returns "blah" (and not an exception)
TimeoutException, according to the spec, is thrown only if the thread waits for the complete timeout period, but no result becomes available. Interruption doesn't fit into this scenario.
Your usage of CountDownLatch is incorrect. You decrement it, but I see no call to latch1.await()
Related
I see in the code here a lot of
executorService.submit(() -> {
// do stuff
}).get();
...and I wonder why is the executorService used like this, submitting something you will immediately get?
Calling an immediate get() forces the ExecutorService to process "do stuff" in the executor service's threadpool rather than the local thread, which may for example choke processing if the maximum number of threads allocated to it is small, despite there being a great many threads running to handle requests.
Consider an obvious example of an executor service that has only 1 thread:
ExecutorService executorService = Executors.newSingleThreadExecutor();
and the example code being called from say an HttpRequestHandler.
By using the immediate get() processing of "do stuff" will be serialized, which may be desirable or a requirement, despite there being many simultaneous requests being processed each in their own thread.
Without the wrapper of executorService.submit(...).get(), processing of "do stuff" would be done in parallel in the request handler's thread, which may be fine or may cause problems if "do stuff" is particularly expensive or constrained in some way if parallelism is unbounded.
Parallelism can be limited/bounded instead of eliminated as follows:
ExecutorService executorService = Executors.newFixedThreadPool(3);
would limit processing to (for example) a maximum of 3 concurrently processing "do stuff"s, despite there being a great many requests being processed simultaneously.
Other more subtle effects are possible to via the choice of Thread in which "do stuff" runs. Consider:
ExecutorService executorService = Executors.newSingleThreadExecutor(myThreadFactory);
will make "do stuff" run in a custom type of thread, rather than in the thread type chosen for the HttpRequestHandler.
submitting something you will immediately get
Just because you submit the task and 'get' it immediately, that doesn't necessarily mean it will be run immediately by the ExecutorService.
Here's a practical example of how this is useful:
You have a web server, which returns weather data. When an HTTP request comes in, you need to make a connection to a weather API to retrieve the weather data.
However, that weather API only allows two concurrent connections.
One way to solve this problem would be to have an ExecutorService with only two available threads.
Now, no matter how many servlet threads simultaneously submit tasks for execution, you can ensure that only two threads at a time can perform requests against the weather API. The servlet threads will block until the weather API is available to provide the servlet with the requested data.
Because somebody blindly copied this from Javadoc, which reads "If you would like to immediately block waiting for a task, you can use constructions of the form result = exec.submit(aCallable).get();"
Apart from that and the slight difference in exception semantics that #Michael mentioned in his comment on the question, there is also a slight difference wrt. interrupting of threads: if // do stuff blocks uninterruptedly you would still be able to interrupt the blocking call to Future.get or cancel the future. Note though, this doesn't do anything to the thread running // do stuff. That thread would keep blocking, only your main thread becomes unblocked.
The only use case that I can think of is when:
code that calls it MUST return some result synchronously (i.e. it's implementing some sync api handling http request or whatnot)
the executor that is called is a ForkJoinPool and the task submitted is the RecursiveTask that will internally fork. This way you could use more than one cpu to execute whole task.
Using a .get() call on a Future allows one to abstract the details of how exactly one delivers the result. Excusing the length of the example, if one looks at the .get() method for the below class, one can see that to implement the same sort of timing mechanism in the calling thread would be an excessive amount of boilerplate code. By abstracting it, the calling thread will simply block indefinitely while the worker thread worries about the details of delivering on the promise of its Future
import java.util.Optional;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
class DecayingRetry<T> implements Future<T> {
protected final ScheduledExecutorService executor;
protected final Callable<T> callable;
private final boolean isOwnExecutor;
protected ScheduledFuture<?> future;
#SuppressWarnings("OptionalUsedAsFieldOrParameterType")
protected Optional<?> result;
protected boolean isDone;
protected boolean isCancelled;
protected final ReentrantLock lock;
private final double maxDelay;
private double initialDelay;
private final TimeUnit timeUnit;
private DecayingRetry(ScheduledExecutorService executor,
boolean isOwnExecutor,
Callable<T> callable,
long initialDelay,
long maxDelay,
TimeUnit timeUnit) {
this.isOwnExecutor = isOwnExecutor;
lock = new ReentrantLock(true);
lock.lock();
this.executor = executor;
this.callable = callable;
isCancelled = false;
isDone = false;
if (maxDelay < 0) {
this.maxDelay = Double.POSITIVE_INFINITY;
} else {
this.maxDelay = maxDelay;
}
lock.lock();
this.initialDelay = (double) initialDelay;
this.timeUnit = timeUnit;
future = executor.schedule(this::delayLoop, initialDelay, timeUnit);
}
public static <T> T on(Callable<T> callable, long initialDelay, long maxDelay, TimeUnit timeUnit) throws Exception {
try {
return Optional.ofNullable(callable.call()).orElseThrow(IllegalStateException::new);
} catch (IllegalStateException ignored) {
try {
return new DecayingRetry<>(Executors.newSingleThreadScheduledExecutor(),
true,
callable,
initialDelay,
maxDelay,
timeUnit).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
System.exit(-1);
}
}
return null;
}
public static <T> T on(Callable<T> callable,
ScheduledExecutorService executor,
long initialDelay,
long maxDelay,
TimeUnit timeUnit) throws Exception {
try {
return Optional.ofNullable(callable.call()).orElseThrow(IllegalStateException::new);
} catch (IllegalStateException ignored) {
try {
return new DecayingRetry<>(executor,
false,
callable,
initialDelay,
maxDelay,
timeUnit).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
System.exit(-1);
}
}
return null;
}
synchronized private void delayLoop() {
if (isDone) {
return;
}
try {
result = Optional.ofNullable(callable.call());
} catch (Exception e) {
result = Optional.of(e);
isDone = true;
return;
}
if (!result.isPresent()) {
if (initialDelay < maxDelay) {
initialDelay *= 1.618033988749; //PHI
initialDelay = Math.min(maxDelay, initialDelay);
}
future = executor.schedule(this::delayLoop, (long) initialDelay, timeUnit);
} else {
isDone = true;
lock.unlock();
}
}
public boolean cancel(boolean mayInterruptIfRunning) {
if (isDone) {
return false;
} else if (future.cancel(mayInterruptIfRunning)) {
isCancelled = true;
isDone = true;
return true;
}
return false;
}
#Override
public boolean isCancelled() {
return isCancelled;
}
#Override
public boolean isDone() {
return isDone;
}
#Override
#NotNull
public T get() throws InterruptedException, ExecutionException {
lock.lock();
while (!isDone) { // lock acquired too early for some reason, so we allow the worker thread to grab it
lock.unlock();
lock.lock();
}
if (result.isPresent()) {
if (result.get() instanceof Throwable) {
throw new ExecutionException((Throwable) result.get());
}
if (isOwnExecutor) {
executor.shutdown();
}
//noinspection unchecked
return (T) result.get();
}
throw new ExecutionException(new IllegalStateException("Retry result was null"));
}
public T get(long timeout, #NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
throw new ExecutionException(new IllegalStateException("Not implemented"));
}
}
I have a method to run that makes connection to server, and when server fails, would wait until it receives a message that server is up again. However, this entire method should have a timeout, and if it is over the time, method should interrupt and return error log instead.
private Semaphore sem = new Semaphore(0);
private TimeUnit unit = TimeUnit.MILLISECONDS;
public String some_method(Object params, long timeout, TimeUnit unit) {
long time = 0;
while(time < timeout) { // not sure about timeout method
try {
//some task that is prone to ServerConnectException
return; // returns value and exits
} catch(ServerConnectException ex) {
sem.acquire();
} catch(InterruptedException uhoh) {
System.out.println("uhoh, thread interrupted");
}
// increment time somehow
}
sem.release();
return null; // a message of task incompletion
}
I was thinking about running a thread containing semaphore that blocks thread if there's a server failure problem, but I cannot seem to organize thread such that it will contain the semaphore but be contained by method itself.
QUESTION:
- However, the method is already in a gigantic class and making separate Thread for just that method will mess up entire call hierarchy as well as whole API, so I don't want to do that. I need some process that runs along with the some_method and places lock and release on its processes as needed, with timeout. What should I be thinking? Some other concurrency wrapper like executor?
Thanks!
Semaphore doesn't seem to be the right concurrency primitive to use here, as you don't really need a utility for locking, but rather a utility to help you coordinate inter-thread communication.
If you need to communicate a stream of values, you would typically use a blocking queue, but if you need to communicate a single value, a CountDownLatch and a variable do the trick. For example (untested):
public String requestWithRetry(final Object params, long timeout, TimeUnit unit) throws InterruptedException {
String[] result = new String[1];
CountDownLatch latch = new CountDownLatch(1);
Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
try {
result[0] = request(params);
latch.countDown();
return;
}
catch(OtherException oe) {
// ignore and retry
}
catch(InterruptedException ie) {
// task was cancelled; terminate thread
return;
}
}
}
});
t.start();
try {
if (!latch.await(timeout, unit)) {
t.interrupt(); // cancel the background task if timed out
}
// note that this returns null if timed out
return result[0];
}
catch(InterruptedException ie) {
t.interrupt(); // cancel the background task
throw ie;
}
}
private String request(Object params) throws OtherException, InterruptedException {
// should handle interruption to cancel this operation
return null;
}
I have a nice and compact code, which does not work as I expected.
public class Test {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
for (;;) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
The output is :
Timeout true
END
Question:
Why does not terminate the future.cancel(true) method the called Runnable?
After the program wrote the "END" to the output, the "r" Runnable is still running.
The problem is that your Runnable is not interruptible: task interruption is a collaborative process in Java and the cancelled code needs to check regularly if it's been cancelled, otherwise it won't respond to the interruption.
You can amend you code as follows and it should work as expected:
Runnable r = new Runnable() {
#Override public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {}
} finally {
System.out.println("FINALLY");
}
}
};
This is always a little bit misleading: The ExceutorService or even the underlying thread scheduler do not know anything about what the Runnable is doing. In your case they don't know that there is a unconditional loop.
All these methods (cancel, done, ...) are related to manage Threads in the Executor structure. cancel cancels the thread from the point of view of the Executor service.
The programmer must test if the Runnable was canceled and must terminate the run() method.
So in your case (if I remember well) something like this:
public class Test {
public static void main(String[] args) {
FutureTask r = new FutureTask () {
#Override
public void run() {
try {
for (;!isCancelled();) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
When you cancel a Future whose Runnable has already begun, the interrupt method is called on the Thread that is running the Runnable. But that won't necessarily stop the thread. Indeed, if it's stuck in a tight loop, like the one you've got here, the Thread won't stop. In this case, the interrupt method just sets a flag called the "interrupt status", which tells the thread to stop when it can.
See the Javadoc for the interrupt method of Thread
Future.cancel() will cancel any queued task or will call Thread.interrupt() on your thread if already running.
You need to interrupt your code
It's your code's responsibility is to be ready for any interruptions. I'd go so far to say that whenever you have a long running task, that you insert some interrupt ready code like this:
while (... something long...) {
... do something long
if (Thread.interrupted()) {
... stop doing what I'm doing...
}
}
How to stop what I'm doing?
You have several options:
If your you are in Runnable.run() just return or break out of the loop and finish the method.
You may be in some other method deep in the code. It may make sense at that point for that method to throw InterruptedException so you would just do that (leaving the flag cleared).
But maybe deep in your code it doesn't make sense to throw InterruptedException. In that case you should throw some other exception, but before that mark your thread interrupted again so the code that catches knows that an interrupt was in progress. Here's an example:
private void someMethodDeepDown() {
while (.. long running task .. ) {
... do lots of work ...
if (Thread.interrupted()) {
// oh no! an interrupt!
Thread.currentThread().interrupt();
throw new SomeOtherException();
}
}
}
Now the exception can propagate an either terminate the thread or be caught, but the receiving code hopefully notices that an interrupt is in progress.
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
In attempts of 100% code coverage, I came across a situation where I need to unit test block of code that catches an InterruptedException. How does one correctly unit test this? (JUnit 4 syntax please)
private final LinkedBlockingQueue<ExampleMessage> m_Queue;
public void addMessage(ExampleMessage hm) {
if( hm!=null){
try {
m_Queue.put(hm);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Right before invoking addMessage(), call Thread.currentThread().interrupt(). This will set the "interrupt" status flag on the thread.
If the interrupted status is set when the call to put() is made on a LinkedBlockingQueue, an InterruptedException will be raised, even if no waiting is required for the put (the lock is un-contended).
By the way, some efforts to reach 100% coverage are counter-productive and can actually degrade the quality of code.
Use a mocking library like Easymock and inject a mock LinkedBlockingQueue
i.e.
#Test(expected=InterruptedException.class)
public void testInterruptedException() {
LinkedBlockingQueue queue = EasyMock.createMock(LinkedBlockingQueue.class);
ExampleMessage message = new ExampleMessage();
queue.put(message);
EasyMock.expectLastCall.andThrow(new InterruptedException());
replay(queue);
someObject.setQueue(queue);
someObject.addMessage(msg);
}
As stated above just make use Thread.currentThread().interrupt() if you caught InterruptedException and isn't going to rethrow it.
As for the unit testing. Test this way: Assertions.assertThat(Thread.interrupted()).isTrue();. It both checks that the thread was interrupted and clears the interruption flag so that it won't break other test, code coverage or anything below.
Another option is to delegate dealing with InterruptedException to Guava's Uninterruptibles, so you don't need to write and test your custom code for it:
import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly;
private final LinkedBlockingQueue<ExampleMessage> queue;
public void addMessage(ExampleMessage message) {
putUninterruptibly(queue, message);
}
One proper way could be customizing/injecting the ThreadFactory for the executorservice and from within the thread factory, you got the handle of the thread created, then you can schedule some task to interrupt the thread being interested.
Demo code part for the overwrited method "newThread" in ThreadFactory:
ThreadFactory customThreadfactory new ThreadFactory() {
public Thread newThread(Runnable runnable) {
final Thread thread = new Thread(runnable);
if (namePrefix != null) {
thread.setName(namePrefix + "-" + count.getAndIncrement());
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
scheduledExecutorService.schedule(new Callable<String>() {
public String call() throws Exception {
System.out.println("Executed!");
thread.interrupt();
return "Called!";
}
},
5,
TimeUnit.SECONDS);
return thread;
}
}
Then you can use below to construct your executorservice instance:
ExecutorService executorService = Executors.newFixedThreadPool(3,
customThreadfactory);
Then after 5 seconds, an interrupt signal will be sent to the threads in a way each thread will be interrupted once in executorservice.
The example code in the question may be testable by calling Thread.currentThread().interrupt(). However, besides the mentioned problems various methods reset the interrupted flag. An extensive list is for example here: https://stackoverflow.com/a/12339487/2952093. There may be other methods as well.
Assuming waiting implemented as follows should be tested:
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException ex) {
// Set the interrupt flag, this is best practice for library code
Thread.currentThread().interrupt();
throw new RuntimeException(ex);
}
A call to Thread.sleep itself clears the interrupted flag, so it cannot be set in advance. It can be tested using its own test thread as follows:
AtomicBoolean threadInterrupted = new AtomicBoolean(false);
Runnable toBeInterrupted = () -> {
try {
methodUnderTest();
} catch (RuntimeException unused) {
// Expected exception
threadInterrupted.set(true);
}
};
// Execute the in an operation test thread
Thread testThread = new Thread(toBeInterrupted);
testThread.start();
// When the test thread is waiting, interrupt
while (!threadInterrupted.get()) {
if (testThread.getState() == Thread.State.TIMED_WAITING) {
testThread.interrupt();
}
}
// Assert that the interrupted state is re-set after catching the exception
// Must be happening before thread is joined, as this will clear the flag
assertThat(testThread.isInterrupted(), is(true));
testThread.join();