在Java中,可以在关闭后重新打开System.in

时间:2014-12-04 05:09:00

标签: java multithreading io console

我有一个多线程控制台应用程序,可以从两个不同的来源获取输入。一个是用户输入控制台,另一个是网络。我使用BufferedReader.readline()来获取用户和块的输入,这很好,除非我在等待时接收网络输入。在这种情况下,我需要通过取消readline()来取消阻止用户线程。

我认为取消它的最好方法是关闭System.in并使readline()抛出异常。在那之后,虽然我需要重新打开它。这可能吗?

2 个答案:

答案 0 :(得分:8)

无法重新开启System.inSystem.outSystem.err。底层本机流是连接到其他进程的文件描述符,或者是应用程序无法识别其身份的文件。关闭基础本机文件描述符后,就无法重新打开它们。

我可以建议的最好的方法是为InputStream对象创建一个包装器System.in类,并对包装器进行编码以将close()视为无操作。或者可以将包装器设置为关闭的"没有实际关闭包裹流的状态。

在您的特定用例中,这不会起作用,因为您需要"从System.in读取时取消阻止被阻止的线程。因此,在您的情况下,您需要从System.in进行非阻塞输入。例如,使用available()方法测试是否有任何要从控制台读取的字符。 (通常可以假设,如果available()返回的数字大于零,您将能够读取整行。)

(它也可以使用Selector实现非阻塞读取,但我不认为有可能为{获得一个"可选择的频道" {1}}对象。)


请注意System.in无法正常工作。根据javadocs的说法,它只有在您从可中断频道阅读时才会起作用。

  • System.in不是可中断的频道,

  • 如果是,则Thread.interrupt()的记录行为是通道被中断关闭。

答案 1 :(得分:1)

我遇到了同样的问题,至少可以说,这个问题并没有被java本身所解决,我觉得很奇怪:我们是否遗漏了什么?

无论如何,感谢Stephen C,这里有一个使用匿名类的想法的例子(内联,为system.in创建扫描器时)

(我使用FilterInputStream而不是InputStream,以便我可以将System.in传递给构造函数)

希望这对你有用处

public class MultiopenScanner {
    public static int scanInt() throws IOException{
        //Scanner sc = new Scanner(System.in);
        Scanner sc = new Scanner(new FilterInputStream(System.in){public void close(){}});
        int res = sc.nextInt();
        sc.close();
        return res;
    }

    public static void main(String[] args) throws IOException {
        int i=1;
        while (i>0) {
            System.out.println("Give me an int please : ");
            //some might need this : System.out.flush();
            i = scanInt();
            System.out.println("got "+i);
        }
        System.out.println("done");
    }
}