Reputation: 3227
Thread.interrupt()
:
Interrupts this thread. Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.
Lets say we have this code:
AtomicBoolean thread1Done = new AtomicBoolean(false);
//write in file
Thread thread1 = new Thread(() -> {
try(var writer = Files.newBufferedWriter(Paths.get("foo.txt"))){
for(int i = 0; i < 10000; i++){
writer.write(i);
writer.newLine();
}
}catch(Exception e){ e.printStackTrace(); }
thread1Done.set(true);
});
//interrupt thread1
Thread thread2 = new Thread(() -> {
while(!thread1Done.get()){
thread1.interrupt();
}
});
thread2.start();
thread1.start();
thread1
never writes anything in the file because of thread1.interrupt()
from thread2
.
It always ends with java.nio.channels.ClosedByInterruptException
at writer.newLine();
and foo.txt
is empty.
Is there a way to interrupt only wait, join and sleep
, and ignore the rest?
I run my code with JDK10 on Windows10 x64.
Upvotes: 2
Views: 1512
Reputation: 3886
If what you want is that to interrupt the thread only if it is block by wait, join and sleep calls and not on IO operations, you can simply check for the thread state before calling interrupt method. You can refer to the api and different states in the link follows.
https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.State.html
And sample code may be like the one below.
while ( ( thread1.getState() == Thread.State.WAITING || thread1.getState() == Thread.State.TIMED_WAITING ) && !thread1Done.get()) {
thread1.interrupt();
}
Upvotes: 1
Reputation: 7630
As it stands your code runs so that Thread 1
finishes writing 10k lines into the output text file, in other words Thread 2
interrupts, but there are no statements in Thread 1
which are interruptible. This is because (I suppose) BufferedWriter
opens the file using uninterruptible I/O .
If you want your long loop in Thread 1
to be interruptible, you can add the following check inside your long running loop:
for(int i = 0; i < 10000; i++){
if (Thread.currentThread().isInterrupted()) { //interruptible loop
break;
}
writer.write(i);
writer.newLine();
System.out.println(i);
}
Then by delaying the interruption from Thread 2
by say 10ms I get that only few hundred entries are being written to the file (without the delay, it gets interrupted immediately).
When I swapped Thread 1
to use interruptible channel
(as is FileChannel extends AbstractInterruptibleChannel
):
Thread thread1 = new Thread(() -> {
FileChannel fc = null;
try (
FileChannel fc = FileChannel.open(Paths.get("foo.txt"),
StandardOpenOption.CREATE, StandardOpenOption.WRITE);
)
{
fc = FileChannel.open(Paths.get("foo.txt"),
StandardOpenOption.CREATE, StandardOpenOption.WRITE
);
for(int i = 0; i < 10000; i++){
fc.write(ByteBuffer.wrap(("" + i).getBytes()));
fc.write(ByteBuffer.wrap(("\n").getBytes()));
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
}
}
... I do get nicely interruptible file writing thread.
Upvotes: 1