我有一个多线程控制台应用程序,可以从两个不同的来源获取输入。一个是用户输入控制台,另一个是网络。我使用BufferedReader.readline()来获取用户和块的输入,这很好,除非我在等待时接收网络输入。在这种情况下,我需要通过取消readline()来取消阻止用户线程。
我认为取消它的最好方法是关闭System.in并使readline()抛出异常。在那之后,虽然我需要重新打开它。这可能吗?
答案 0 :(得分:8)
无法重新开启System.in
,System.out
或System.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");
}
}