繁体   English   中英

如何停止等待来自System.in的线路?

[英]How to stop waiting for line from System.in?

我有一项从标准输入执行读取的服务。 这里是

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在这里不是一个很好的选择...

如果主线程对它最终试图关闭的流具有独占访问权,那么您的期望是正确的。 但这不是事实,这就是该程序演示等待的原因。 当您按Enter键(这是行缓冲流,例如System.in刷新内容)时,程序将按预期方式退出。

为了说明,请执行以下操作:

  1. 重命名main service reader方法。
  2. 在终端中运行程序。
  3. 当程序等待您按Enter ,在另一个终端上: jps -v ReaderService查找运行ReaderService的JVM进程(p),然后执行jstack <p> 这为您带来了Java线程转储

您应该得到类似的内容(为简洁起见,省略了其他线程):

"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状态,等待获取表示可变共享状态(在这种情况下, main线程与线程t共享)的BufferedReader上的锁。 如预期的那样,线程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;
        }
    }
}

如果您这样做,还将看到一些有趣的行为:

  1. 在Unix终端上,创建一个文本文件x ,其中包含一些文本。
  2. 运行java ReaderService < x

也许这种行为更接近您的期望。 但是,这与各种流类型的I / O缓冲的工作方式有关。

阅读前检查reader.ready()。 如果为假,则检查关闭标志并睡眠100毫秒左右。

这并不理想,但是我认为这是在System.in上超时的最佳方法。 不过,这仅适用于System.in -如果您正在使用套接字,则应使用实时超时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM