我有一个从标准输入执行读取的服务。这是
public class ReaderService{
private BufferedReader reader;
private volatile boolean closed;
public void start(){
while(!closed){
reader = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println(reader.readLine());
} catch (IOException e) {
System.out.println("IOException");
}
}
}
public void stop(){
try {
reader.close();
} catch (IOException e) {
System.exit(1);
}
closed = true;
}
}
我按如下方式使用它:
public static void main(String[] args) throws InterruptedException{
Thread t = new Thread(new Runnable() {
public void run() {
reader.start();
}
});
t.start();
Thread.sleep(5000);
reader.stop();
}
问题是调用ReaderService::stop()
不会中断对下一行的玷污。我以为它会抛出IOExecption
。
有没有办法从另一个线程“中断”这样的服务?也许BufferedReader
在这里不是一个很好的选择...
答案 0 :(得分:2)
如果主线程拥有对它最终尝试关闭的流的独占访问权限,那么您的期望是正确的。但这不是这里的情况,这就是为什么这个程序展示了等待。当您按下回车键(这是行缓冲流,如System.in
刷新内容时),程序将按预期退出。
为了说明,请执行以下操作:
reader
方法中的main
重命名为service
。Enter
时,在另一个终端:jps -v
- 找到运行ReaderService
的JVM进程(p),然后执行jstack <p>
1}}。这将为您带来 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
源代码(在JDK 1.8中的第522行左右):
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
如果你这样做,你也会看到一些有趣的行为:
x
,其中包含一些文本。java ReaderService < x
。 也许这种行为更接近你的期望。但它与I / O缓冲如何适用于各种类型的流有关。
答案 1 :(得分:1)
在阅读之前检查reader.ready()。如果它是假的,那么检查关闭的标志并睡眠100ms左右。
它并不理想,但我认为这是在System.in上超时的最佳方法。这只适用于System.in,但如果您正在为套接字服务,那么您应该使用实际超时。