Your expectation is right, if the main thread had an exclusive access to the stream that it eventually tries to close. But that is not the case here and that's why this program demonstrates the wait. When you press an enter (which is when the line buffered stream like System.in
flushes the contents), the program exits as expected.
To illustrate, do the following:
- Rename your
reader
in the main
method to service
.
- Run your program in a terminal.
- While the program is waiting for you to press an
Enter
, in another terminal: jps -v
-- find the JVM process (p) that runs ReaderService
and then do a jstack <p>
. This brings you a Java Thread Dump.
You should get something like (other threads omitted for brevity):
"main" #1 prio=5 os_prio=31 tid=0x00007fef4d803000 nid=0xf07
waiting for monitor entry [0x000000010b7a3000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.io.BufferedReader.close(BufferedReader.java:522)
- waiting to lock <0x000000076ac47f78> (a java.io.InputStreamReader)
at ReaderService.stop(ReaderService.java:19)
at ReaderService.main(ReaderService.java:34)
"Thread-0" #10 prio=5 os_prio=31 tid=0x00007fef4c873800 nid=0x5503 runnable [0x000000012b497000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
- locked <0x000000076ab1bf10> (a java.io.BufferedInputStream)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x000000076ac47f78> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x000000076ac47f78> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at ReaderService.start(ReaderService.java:10)
at ReaderService$1.run(ReaderService.java:29)
at java.lang.Thread.run(Thread.java:745)
As you can see, after the main
thread is done sleeping, it goes into a BLOCKED
state waiting to acquire the lock on the BufferedReader
that represents a mutable shared state (which in this case main
thread shares with the thread t
). As expected, the thread t
has already locked the BufferedReader
's lock 0x000000076ac47f78
and has entered the critical section. Note that t
is in RUNNABLE
state, only waiting for someone to press Enter
. Once that happens, the things should return to normal since eventually, main
thread should succeed in acquiring the lock as in BufferedReader.java
source code (around line 522 in JDK 1.8):
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
You'll also see some interesting behavior if you do:
- On a Unix terminal, create a text file
x
with some text in it.
- Run
java ReaderService < x
.
Perhaps that behavior is closer to your expectation. But it has to do with how I/O buffering works for various types of streams.