While solving the task, I've noticed a behavior I can not explain.
My task was to read from InputStream and interrupt that reading after a timeout. Even though lots of people say blocking read can not be interrupted, I've achieved that goal using CompletableFuture
public void startReader() {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> doRead(System.in));
future.get(5, TimeUnit.SECONDS);
}
private void doRead(InputStream in) {
try {
new BufferedReader(new InputStreamReader(in)).readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
But when I implement the same using Future, I can see TimeoutException been thrown into JVM, but I still can see that reading thread was not terminated and still running.
public void startReader() throws ExecutionException, InterruptedException, TimeoutException {
Future<?> future = Executors.newSingleThreadExecutor().submit(() -> doRead(System.in));
future.get(5, TimeUnit.SECONDS);
}
private void doRead(InputStream in) {
try {
new BufferedReader(new InputStreamReader(in)).readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
Why there is such a difference? I believe CompletableFuture does not make any magic
Neither of your code snippets will stop the "reading" thread when you reached the future.get(5, TimeUnit.SECONDS);. They will continue waiting for your input from System.in. If you want to stop it you should send an interrupt to that thread and hope the thread react on it. Or you can force kill the thread, obviously.
However, the CompletableFuture.runAsync() and Executors.newSingleThreadExecutor() calls use different threads, specially using different daemon flags (see What is a daemon thread in Java?). When you place a System.out.println(Thread.currentThread().isDaemon()); inside your doRead() method you will see that CompletableFuture.runAsync uses a daemon thread (so it doesn't block the JVM from terminating) where Executors.newSingleThreadExecutor() does not (and keeps the JVM alive).
Related
I am trying a java program to understand working of Future.
I wrote following program and it never ends. If I put a value that is less than 10 in Thread.sleep(), then it works but not for values >=10.
I understood the part that is causing problem is probably the future.get call.
However, on further analysis, what I tried was, to handle all the exceptions and not letting jvm handle them.
eg:
Now it terminated fine.
I did a further check and saw that if I throw ExecutionException and InterruptedException and handle TimeoutException it works fine again.
Here strange part is I have to compulsorily handle TimeoutException, else it will not work. I am not so sure why this strange behaviour persists.
I am using OpenJDK 15.
If anybody wants to try code snippet its here:
import java.util.concurrent.*;
public class FixedThreadPoolExecutorDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
workWithFutureCallable(executorService);
executorService.shutdownNow();
}
private static void workWithFutureCallable(ExecutorService executorService) throws ExecutionException, InterruptedException, TimeoutException {
Future<Integer> myOtherFuture = executorService.submit(() -> {
try {
Thread.sleep(109);
} catch (InterruptedException e) {
}
return 1000;
});
System.out.println("myOtherFuture should be cancelled if running for more than specified time. ->" + myOtherFuture.get(10, TimeUnit.MILLISECONDS));
}
}
The TimeoutException is not being caught in main, so main is also terminating abruptly without calling shutdownNow. The main thread is terminated but the threads created by Executors are non-daemon by default, so the virtual machine is not shut down, the Executors thread(s) continue running.
Solution:
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
workWithFutureCallable(executorService);
} finally {
executorService.shutdownNow();
}
}
or
implement a ThreadFactory to create daemon threads and use it to get the service:
ExecutorService executorService = Executors.newFixedThreadPool(2, r -> {
var thread = new Thread(r);
thread.setDaemon(true);
return thread;
});
Even better, at least in production code, catch and handle the Exceptions (together with the finally block.)
I have a thread, inside its making a database call that sometimes hangs, normally timeout should be handle in the client library, but in this case the client library doesn't handle it correctly so I have to add an extra scheduled job to cancel the thread that is making db call if it takes too long to avoid back pressure.
Right now I am terminating the thread through
final Future handler = executor.submit(new MyTask());
executor2.schedule(new Runnable(){
public void run(){
handler.cancel(true);
}
}, 3, TimeUnit.SECONDS);
Is there a proper way to interrupt a thread without TimeUnit.MILLISECONDS.sleep(1); ? Adding sleep seems hacky
#Override
public Boolean call() {
try {
// Sometimes hangs
db.call();
// Need it to be here to call InterruptedException
TimeUnit.MILLISECONDS.sleep(1);
return true;
} catch (InterruptedException e) {
return false;
}
}
Is there a proper way to interrupt a thread without TimeUnit.MILLISECONDS.sleep(1); ?
This doesn't interrupt a thread. It merely checks if the thread has been interrupted, either before or during the sleep, and throws an InterruptedException if it was.
If you want to interrupt a thread, use:
t.interrupt();
If you want to check if the current thread has been interrupted, use:
Thread.interrupted()
Note that this clears this interrupted state: use Thread.currentThread().isInterrupted() to check without clearing the state.
As of Java 9, you can use CompletableFuture.orTimeout:
Future<?> handler = CompletableFuture.runAsync(new MyTask())
.orTimeout(3, TimeUnit.SECONDS);
I have a situation where I'm using a Thread, she call a method that will do multiple processes, I need to use a "cancel" button in which you have to stop the thread, I not can use: "while" ,to verify that it was canceled because it not has loop in this process.
Ex:
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
controller = new FirstEtapaController();
execProcess();
return null;
}
};
new Thread(task).start();
Call Method
private void execProcess() {
Thread thread = new Thread(new Runnable() {
public void run() {
getController().execMhetod();
refreshTable();
}
});
thread.start();
thread.join();
};
Ie, I need to stop this process, even when the "ExecMethod" already running, it will take minutes, so I've gotta stop it and not have to wait for him to finish so that , others do not continues.
Remembering that this process will do iteration with my DAO.
The only way (well behaved way) is to add logic points in you spawned threads to check for an interrupted state. You can choose to use the built-in Thread.interrupt() mechanisms, or add your own logic using some form of thread-safe variable (an AtomicBoolean?) or a Semaphore of some sort.
If you use the Thread.interrupt() then your child processes will throw an InterruptedException when they encounter certain conditions, like Thread.wait() and other methods which require synchronization or use the java.util.concurrent.* classes.
You will need to (should already be) handle the InterruptedExceptions in the threads anyway, but perhaps you will need to put regular 'checks' in your child processes to look for the interrupted state anyway (can use Thread.isInterrupted() )
It is worth reading this Handling InterruptedException in Java
If instead of a raw Thread if you use an ExecutorService you'll end up with lots of additional methods/levers to control your threads, one of which is shutdownAll() which uses Thread.interrupt() to kill your thread and lets you check thread status via isTerminated()
Your user interface does not have to wait for the worker thread to finish, so don't worry too much about that.
Alas, Thread.destroy() and Thread.stop() are deprecated, due to bad implementations. I don't think there is a good "sig-kill" type of substitute for Java threads. You are going to have to recode the worker to check an abort flag of some kind, if it matters much. Otherwise, just let it waste a little CPU. ("you can't cancel that Save -- I've already done it!", in effect)
Whether or not a task can be canceled really depends on its implementation. Typically it intermittently checks a flag whether it should continue or not.
You can implement such a flag yourself, and a method to set it :
private volatile boolean shouldStop;
public void cancel() {
shouldStop = true;
}
#Override
public void run() {
while (!shouldStop) {
// do work
}
}
But threads already come with a flag : the interrupted flag. And while it is not necessarily used for canceling a thread, it is typical to use it for exactly that purpose. In fact the standard ExecutorService implementations will try to cancel their threads by interrupting them.
Aside from that several blocking methods (methods that put a thread in BLOCKED or WAITING state) will throw an InterruptedException when the thread is interrupted, at which point they become RUNNABLE again. This is something the previous approach with a boolean flag cannot achieve.
Therefore it is a better approach to use interruption to allow a task to be canceled. And you do not really need that cancel() method any more either :
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// do work
}
}
As a bonus, any code that knows your thread, knows how to cancel it. Including standard ExecutorService implementations.
Care should be taken when catching an InterruptedException, since doing that clears the interrupted flag. It is adviseable to always restore the interrupted flag when catching the Exception, so clients also know it's time to stop doing what they're doing.
private BlockingQueue<Integer> queue;
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Integer id = queue.take(); // blocking method
// do work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
To cancel a thread, you can simply keep a reference to the Thread object and call interrupt() on it :
Thread thread = new Thread(new InterruptibleTask());
thread.start();
// some time after :
thread.interrupt();
But a more elegant approach is keeping tabs on your task (and not so much the specific thread it runs on) through a Future object. You can do this by wrapping your Runnable or Callable in a FutureTask.
RunnableFuture<Void> task = new FutureTask<>(new InterruptibleTask(), null);
new Thread(task).start();
// some time after :
task.cancel(true); // true indicating interruption may be used to cancel.
A Future is key in controlling your task. It allows you to wait for its completion, and optionally receive a value the task calculated :
try {
String value = future.get(); // return value is generically typed String is just as example.
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // since future.get() blocks
} catch (ExecutionException e) {
logger.log(Level.SEVERE, "Exception on worker thread", e.getCause()); // the ExecutionException's cause is the Exception that occurred in the Task
}
If you have several tasks (or even just one) it is worth using an ExecutorService :
ExecutorService pool = Executors.newCachedThreadPool();
Future<?> submit = pool.submit(new InterruptibleTask());
pool.shutdownNow(); // depending on ExecutorService implementation this will cancel all tasks for you, the ones Executors returns do.
I'm currently attempting to write a Logger style thread. I'm not using the existing API because this is partially an exercise to improve my threading.
When the thread is interrupted, I need it to shutdown gracefully, flushing the last of it's queued messages and closing the file streams.
Currently, it shuts down but messages are often still in queue, and I'm concerned that the file streams aren't being closed gracefully.
This is my run()
while(!shutdown){
writeMessages();
try{
Thread.sleep(5000);
}
catch (InterruptedException e) {
}
}try {
writeMessages();
} catch (CustomException e1) {
e1.printStackTrace();
}
try {
logFile.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
errFile.close();
} catch (IOException e) {
e.printStackTrace();
}
Java has very neat way to shutdown threads. It's called interruption flag. When you want to interrupt thread you simply write following code:
thread.interrupt();
thread.join();
And in the Runnable of background thread you should check interruption flag and behave accordingly. If you want thread to survive until messages are left you can do it in a following manner (I assume you have some way of checking is there any messages left. In my case it's a BlockingQueue):
Thread self = Thread.currentThread();
BlockingQueue<String> messages = ...;
while (!self.isInterrupted() || !messages.isEmpty()) {
try {
String message = messages.take();
writeMessage(message);
} catch (InterruptedException) {
self.interrupt();
}
}
One more thing. You should ensure that messages are not added to the queue after thread shutdown is requested or shutdown all threads generating messages before writing thread. This also could be done checking thread interruption flag (you need to know reference to a writer thread):
public void addMessage(String message) {
if (thread.isInterrupted() || !thread.isAlive()) {
throw new IllegalStateException();
}
messages.add(message);
}
Also I recommends you to see at java.util.concurrent package. It have a lot of useful tools for multithreaded applications.
Use the finally block to add your flushing instructions.
All other comments are good, I just want to add - make sure that you called flush() on your output streams before closing them.
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();