如何中断scanner.nextline()调用

关于打断读取系统的问题有很多线索。但是我在这里寻找的是如何最好地编写我想要实现的内容的一些建议。

我有一个getlogin()方法需要执行以下操作:要求用户输入所需的登录环境详细信息,如果在6秒后用户没有输入有效值(“live”或“test”),则将userlogin变量设置为“测试”并将其返回给调用者。

我为getlogin()实现采用了以下方法:

1 – 启动两个执行以下操作的线程: – thread1创建一个scanner对象,然后调用scanner.nextline(),并根据用户输入设置变量userlogin。 在退出thread1之前中断thread2。 – thread2等待6秒,如果仍未设置userlogin,则为userlogin设置默认值。 在退出thread2之前中断thread1。

2 – 加入thread2以阻止主线程返回null userlogin

3 – 返回userlogin

我遇到的问题是,当thread2调用thread1.interrupt时,scanner.nextline()不会中断,这就是为什么我不在第2步中加入thread1,因为主线程会挂起。 在thread2中断后有没有办法让thread1完成? 或者这种方法是否完全过度,并且有一种更简单的方法来实现合同?

最简单的解决方案是在“读取”线程中公开底层流,并从超时线程中关闭该流。 这应该会中断读取并引发exception。 处理此exception,您应该能够继续执行逻辑。 唯一的问题是你将无法再次重复使用相同的流。 不幸的是,没有简单的方法来处理阻塞系统调用的中断。

编辑:

遵循完全不同的推理路线; 由于我们无法关闭输入流只是为了打断它,我能想到的唯一方法就是使用Robot类提供的“编程用户输入”function。 这是一个适合我的例子:

import java.awt.Robot; import java.awt.event.KeyEvent; import java.util.Scanner; import java.util.concurrent.TimeUnit; public class ConsoleTest { /** * @param args */ public static void main(String[] args) { new TimeoutThread().start(); new ReaderThread().start(); } } class ReaderThread extends Thread { @Override public void run() { System.out.print("Please enter your name: "); try(Scanner in = new Scanner(System.in)) { String name = in.nextLine(); if(name.trim().isEmpty()) { name = "TEST"; // default user name } System.out.println("Name entered = " + name); } } } class TimeoutThread extends Thread { @Override public void run() { try { Thread.sleep(TimeUnit.SECONDS.toMillis(5)); Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_ENTER); robot.keyRelease(KeyEvent.VK_ENTER); } catch(Exception e) { e.printStackTrace(); } } } 

上面的代码使用的逻辑是,一旦超时到期,我们就会模拟一个新行,这将导致“name”变量为空。 然后我们有一个检查,它执行必要的逻辑并设置适当的用户名。

关于上述方法的问题是它:

  • 使用机器人类AWT所以可能无法很好地使用无头终端(?)
  • 假设焦点窗口是控制台窗口。 如果焦点位于其他位置,则会为该窗口注册ENTER键,而不是应用程序窗口。

希望这可以帮助你。 我现在真的没有想法了。 🙂

还可以使用FutureTask和lambda表达式:

 FutureTask readNextLine = new FutureTask(() -> { return scanner.nextLine(); }); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(readNextLine); try { String token = readNextLine.get(5000, TimeUnit.MILLISECONDS); ... } catch (TimeoutException e) { // handle time out } 

如果有要读取的字节,为什么不用System.in.available()轮询? 它是非阻塞的:当确定它有效并且不阻塞时,可以调用阻塞的Scanner.nextLine()。

geri的另一个版本的答案是:

 ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(() -> { try (Scanner in = new Scanner(System.in)) { return in.nextLine(); } }); try { return future.get(5, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e1) { return ...; }