关于中断读取系统的问题有很多线索。但我在这里寻找的是如何最好地编写我想要实现的内容的一些建议。
我有一个getlogin()
方法需要执行以下操作:要求用户输入所需的登录环境详细信息,如果6秒后用户没有输入有效值(“实时”或“测试”)然后将userlogin变量设置为“test”并将其返回给调用者。
我对getlogin()
实施采用了以下方法:
启动两个执行以下操作的线程:
thread1
创建一个扫描仪对象,然后调用scanner.nextline()
,并根据用户输入设置变量userlogin
。在退出thread1
之前中断thread2。thread2
等待6秒,如果仍未设置userlogin
,则设置userlogin
的默认值。在退出thread1
之前中断thread2
。加入thread2
以阻止主Thread
返回userlogin
为空
返回用户登录
我遇到的问题是scanner.nextline()
在thread2
调用thread1.interrupt
时不会中断,这就是为什么我不在步骤2中加入thread1
作为主Thread
会挂起。
在thread1
中断后,有没有办法让thread2
完成?或者这种方法是否完全过度,并且有一种更简单的方法来实现合同?
答案 0 :(得分:4)
最简单的解决方案是在“读取”线程中公开底层流,并从超时线程中关闭该流。这应该会中断读取并引发异常。处理此异常,您应该能够继续执行逻辑。唯一的问题是你将无法再次重复使用相同的流。不幸的是,没有简单的方法来处理阻塞系统调用的中断。
修改强>
遵循完全不同的推理方式;鉴于我们无法关闭输入流只是为了打断它,我能想到的唯一方法就是使用Robot类提供的“编程用户输入”功能。这是一个适合我的例子:
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”变量为空。然后我们有一个检查,它执行必要的逻辑并设置适当的用户名。
关于上述方法的问题在于:
ENTER
按键,而不是应用程序窗口。希望这会帮助你。我现在真的没有想法了。 :)
答案 1 :(得分:0)
还可以使用FutureTask和lambda表达式:
FutureTask<String> readNextLine = new FutureTask<String>(() -> {
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
}
答案 2 :(得分:0)
如果有要读取的字节,为什么不用System.in.available()轮询?它是非阻塞的:可以调用Scanner.nextLine(),当它确定有效并且不阻塞时阻塞它。
答案 3 :(得分:-1)
geri的另一个版本的答案是:
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> 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 ...;
}