在Java中从控制台获取输入:是阻塞还是非阻塞?
我正在编写一个Java程序,在这个程序中,我从控制台读取一行代码,并围绕它进行一些处理。处理可能需要1-2秒(即比输入速率长),而我可能保持每秒接收50行 虽然也有一些类似的问题,但它们是针对C/C++而不是Java。因此,我的基本问题如下: 仍在处理输入/行时,是否阻止我接收新输入?或者它们以某种方式在系统/JVM中排队?或者最好这样问:当处理需要时间时,我是否会漏掉任何一行?我不想以任何方式漏掉任何一行 以下是我的代码片段:在Java中从控制台获取输入:是阻塞还是非阻塞?,java,java.util.scanner,Java,Java.util.scanner,我正在编写一个Java程序,在这个程序中,我从控制台读取一行代码,并围绕它进行一些处理。处理可能需要1-2秒(即比输入速率长),而我可能保持每秒接收50行 虽然也有一些类似的问题,但它们是针对C/C++而不是Java。因此,我的基本问题如下: 仍在处理输入/行时,是否阻止我接收新输入?或者它们以某种方式在系统/JVM中排队?或者最好这样问:当处理需要时间时,我是否会漏掉任何一行?我不想以任何方式漏掉任何一行 以下是我的代码片段: Scanner sc = new Scanner(System.i
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
//process line. Can take 1-2 seconds.
processInput(sc.nextLine());
}
sc.close();
更新:
正如建议的那样,我提出了使用执行器使代码更加线程友好的方法:
ExecutorService executorService = Executors.newFixedThreadPool(10);
while (sc.hasNext()) {
executorService.submit(new Runnable() {
public void run() {
processInput(sc.nextLine());
}
});
}
它是阻塞,尽管可能更清楚:它一直在说“扫描操作可能会阻塞等待输入”。虽然理论上它可以抛出NosTouchElementException而不是阻塞,但在我看来,这取决于实现。只需比较这两个示例:
第一,线性,无多个螺纹:
public class SampleClass {
public static void main(String[] args) {
SampleClass instance = new SampleClass();
instance.start();
}
private void start() {
Scanner sc = new Scanner(System.in);
String input;
while (!(input = sc.nextLine()).equals("exit")) {
processInput(input);
}
sc.close();
}
private void processInput(String input) {
try {
Thread.sleep(2000);
System.out.println("input: " + input);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
然后,为每个输入处理使用一个新线程:
public class SampleClass {
public static void main(String[] args) {
SampleClass instance = new SampleClass();
instance.start();
}
private void start() {
Scanner sc = new Scanner(System.in);
String input;
while (!(input = sc.nextLine()).equals("exit")) {
processInput(input);
}
sc.close();
}
private void processInput(String input) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println("input: " + input);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
试试看。在这两种情况下,您都不会错过输入,但不同的是,如果没有新线程,处理时间会增加(当然)-它不会并行运行。如果processInput()
没有在另一个线程中运行内容,则会等待处理完成并获得下一行,然后重试。但是系统中的是一个数据流。你不会因为花时间从小溪里阅读而“漏掉”任何一行。@mumpitz说得好。我应该在新线程中运行processInput
。只是想知道,这些即将发布的消息堆放在哪里?!:)@TinaJ他们不是;)在process()
完成之前,您将无法输入另一行。因为只有在这之后,它才允许您输入下一行。我听说最好有一个执行者池,他们可以在那里执行processInput
。有什么例子可以实现吗?@mumpitz yes no stacked…我的意思是输入是在控制台中输入的,但我仍然没有在我的代码中作为新行接收它们。那么他们同时在哪里缓冲?谢谢。问题更多的是:当处理需要时间时,我会错过任何输入吗?原则上不会。但请注意,“如果没有外部同步,扫描仪对于多线程使用是不安全的。”嗯,那个么,我该如何使我的代码片段高效呢?我听说了遗嘱执行人的事。如果有帮助的话,你可以发布一个示例吗?如果线程处理是在processInput中完成的,你可以使用一个执行器。@Jonathan在现实世界中你是100%正确的,但我认为它们不能更具体,因为阻塞是由OSTool完成的。是的,就是这样。但在这里你每秒钟就加一次线程,对吗?!你能检查我的更新,看看我对执行器的使用是否正确吗?每次收到新输入时,都会启动一个新线程。然后,该线程等待2秒钟,然后将输入打印到stdout并退出。我自己也没有和遗嘱执行人一起工作过,但看起来不错,而且非常实用。