Ваши ожидания верны, если основной поток имел эксклюзивный доступ к потоку, который в конечном итоге пытается закрыть. Но это не так, и поэтому эта программа демонстрирует ожидание. Когда вы нажимаете кнопку ввода (то есть, когда строка буферизует, поток, такой как System.in
, сбрасывает содержимое), программа завершается так, как ожидалось.
Чтобы проиллюстрировать это, выполните следующие действия:
- переименовывать
reader
в методе main
к service
.
- Запустите программу в терминале.
- Пока программа ждет вас, чтобы нажать
Enter
, в другом терминале: jps -v
- найдите процесс JVM (p), который запускается ReaderService
, а затем выполните jstack <p>
. Это приносит вам Java Thread Dump.
Вы должны получить что-то вроде (другие потоки опущенных для краткости):
"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)
Как вы можете видеть, после того, как main
нити делается спать, он переходит в BLOCKED
состояние ждет, чтобы получить блокировку на BufferedReader
, который представляет собой изменяемое разделяемое состояние (которое в этом случае обходит нить main
потоком t
). Как и ожидалось, нить t
уже заблокировала блокировку BufferedReader
0x000000076ac47f78
и вошла в критический раздел. Обратите внимание, что t
находится в RUNNABLE
состоянии, только ожидая, что кто-то нажмет Enter
. Как только это произойдет, все должно вернуться к нормальной жизни, так как в конце концов, main
нить должна добиться успеха в приобретении замка, как в BufferedReader.java
исходном коде (вокруг линии 522 в JDK 1.8):
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
Вы также увидите некоторое интересное поведение если вы это сделаете:
- На терминале Unix создайте текстовый файл
x
с некоторым текстом в нем.
- Пробег
java ReaderService < x
.
Возможно, это поведение ближе к вашему ожиданию. Но это связано с тем, как буферизация ввода-вывода работает для различных типов потоков.
Может быть полезным: http://stackoverflow.com/questions/6008177/java-how-to-abort-a-thread-reading-from-system-in – acdcjunior
@acdcjunior Интересно, поэтому просто проверяйте периодически, если мы есть ли данные для завершения readLine - это только путь? – stella
, когда вы хотите, чтобы поток 'прерывал' – emotionlessbananas