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

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

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

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

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

在您的特定用例中,这将无效,因为您“需要”在从System.in读取时解除阻塞的线程。 因此,在您的情况下,您需要从System.in进行非阻塞输入。 例如,使用available()方法测试是否有任何要从控制台读取的字符。 (通常可以安全地假设,如果available()返回一个大于零的数字,您将能够读取整行。)

(它也可以使用Selector实现非阻塞读取,但我认为不可能为System.in对象获取“可选择的通道”。)


请注意, Thread.interrupt()将不起作用。 根据javadocs,它只有在您从可中断频道阅读时才会起作用。

  • System.in不是可中断的通道,并且

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

我遇到了同样的问题,我发现奇怪的是,至少可以说这个问题并没有被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"); } }