用户输入超时 Java
User input with a timeout in Java
我正在尝试构建具有此功能的命令行界面:如果用户花费超过 15 秒来插入输入(在本例中为整数),则该函数会做出默认选择 (0)。下面的代码是我到目前为止写的,它工作正常。
问题是我想添加一个新功能:如果用户输入了错误的数字(<0 或 >range),控制台应该打印类似 ("Wrong choice, you have to pick an integer between 0 - "+ range);
的内容
但是,当控制台打印消息时,计时器仍应 运行 并在 15 秒后结束此循环,以防用户不断输入错误的数字。如果用户最终得到一个正确的数字,它应该立即中断循环。
这是我的代码,但我对如何添加功能没有清晰的想法,因为我对 Future、Callable 和 Executor 功能比较陌生。如果谁有这方面的经验,我很乐意学习!
private int getChoiceWithTimeout(int range){
Callable<Integer> k = () -> new Scanner(System.in).nextInt();
Long start= System.currentTimeMillis();
int choice=0;
ExecutorService l = Executors.newFixedThreadPool(1); ;
Future<Integer> g;
System.out.println("Enter your choice in 15 seconds :");
g= l.submit(k);
while(System.currentTimeMillis()-start<15*1000 && !g.isDone()){
// Wait for future
}
if(g.isDone()){
try {
choice=g.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
g.cancel(true);
return choice;
}
是的,所以您要做的是提交未来并调用 Future#get() 并使用 TimeUnit 和 Long 参数来指示在放弃 operation/execution 之前要阻止的阈值。
值得注意的是,ThreadPoolExecutor 不应该这样使用。它应该在方法之外定义并重新使用,然后在应用程序终止或不再需要时关闭。
private int getChoiceWithTimeout(int range){
Callable<Integer> callable = () -> new Scanner(System.in).nextInt();
ExecutorService service = Executors.newFixedThreadPool(1);
System.out.println("Enter your choice in 15 seconds :");
Future<Integer> inputFuture = service.submit(callable);
try {
return inputFuture.get(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException("Thread was interrupted", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Something went wrong", e);
} catch (TimeoutException e) {
// tell user they timed out or do something
throw new IllegalStateException("Timed out! Do something here OP!");
} finally {
service.shutdown();
}
}
您可以使用 labelled break(下面给出的代码中的 done:
)和一个 boolean
变量(下面给出的代码中的 valid
)来跟踪输入是否有效。
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getChoiceWithTimeout(10));
}
static int getChoiceWithTimeout(int range) {
Callable<Integer> k = () -> new Scanner(System.in).nextInt();
Long start = System.currentTimeMillis();
int choice = 0;
boolean valid;
ExecutorService l = Executors.newFixedThreadPool(1);
Future<Integer> g;
System.out.println("Enter your choice in 15 seconds :");
g = l.submit(k);
done: while (System.currentTimeMillis() - start < 15 * 1000) {
do {
valid = true;
if (g.isDone()) {
try {
choice = g.get();
if (choice >= 0 && choice <= range) {
break done;
} else {
throw new IllegalArgumentException();
}
} catch (InterruptedException | ExecutionException | IllegalArgumentException e) {
System.out.println("Wrong choice, you have to pick an integer between 0 - " + range);
g = l.submit(k);
valid = false;
}
}
} while (!valid);
}
g.cancel(true);
return choice;
}
}
一个示例 运行: 不要输入任何内容,该方法将在 15 秒后 return 和 0
,就是这样当前正在使用您的代码
Enter your choice in 15 seconds :
0
另一个示例运行: 一旦用户输入有效数字,该方法将return 与输入的值;否则,它将在 15 秒后继续请求有效输入或 return 0
。
Enter your choice in 15 seconds :
a
Wrong choice, you have to pick an integer between 0 - 10
12
Wrong choice, you have to pick an integer between 0 - 10
5
5
注意: 使用标记的 break
不是强制性的,您可以将其替换为传统的 break
ing 方式,但这需要您添加多几行代码。
这是一个简化的较短版本,如果用户没有输入内容,它会在 n 秒后超时:
private static final ExecutorService l = Executors.newFixedThreadPool(1);
private static String getUserInputWithTimeout(int timeout) {
Callable<String> k = () -> new Scanner(System.in).nextLine();
LocalDateTime start = LocalDateTime.now();
Future<String> g = l.submit(k);
while (ChronoUnit.SECONDS.between(start, LocalDateTime.now()) < timeout) {
if (g.isDone()) {
try {
String choice = g.get();
return choice;
} catch (InterruptedException | ExecutionException | IllegalArgumentException e) {
logger.error("ERROR", e);
g = l.submit(k);
}
}
}
logger.info("Timeout...");
g.cancel(true);
return null;
}
public static void main(String[] args) {
logger.info("Input the data in 10 seconds or less...");
String res = getUserInputWithTimeout(10); // 10s until timeout
if(res != null) {
logger.info("user response: [" + res + "]");
}
System.exit(0);
}
我正在尝试构建具有此功能的命令行界面:如果用户花费超过 15 秒来插入输入(在本例中为整数),则该函数会做出默认选择 (0)。下面的代码是我到目前为止写的,它工作正常。
问题是我想添加一个新功能:如果用户输入了错误的数字(<0 或 >range),控制台应该打印类似 ("Wrong choice, you have to pick an integer between 0 - "+ range);
但是,当控制台打印消息时,计时器仍应 运行 并在 15 秒后结束此循环,以防用户不断输入错误的数字。如果用户最终得到一个正确的数字,它应该立即中断循环。
这是我的代码,但我对如何添加功能没有清晰的想法,因为我对 Future、Callable 和 Executor 功能比较陌生。如果谁有这方面的经验,我很乐意学习!
private int getChoiceWithTimeout(int range){
Callable<Integer> k = () -> new Scanner(System.in).nextInt();
Long start= System.currentTimeMillis();
int choice=0;
ExecutorService l = Executors.newFixedThreadPool(1); ;
Future<Integer> g;
System.out.println("Enter your choice in 15 seconds :");
g= l.submit(k);
while(System.currentTimeMillis()-start<15*1000 && !g.isDone()){
// Wait for future
}
if(g.isDone()){
try {
choice=g.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
g.cancel(true);
return choice;
}
是的,所以您要做的是提交未来并调用 Future#get() 并使用 TimeUnit 和 Long 参数来指示在放弃 operation/execution 之前要阻止的阈值。
值得注意的是,ThreadPoolExecutor 不应该这样使用。它应该在方法之外定义并重新使用,然后在应用程序终止或不再需要时关闭。
private int getChoiceWithTimeout(int range){
Callable<Integer> callable = () -> new Scanner(System.in).nextInt();
ExecutorService service = Executors.newFixedThreadPool(1);
System.out.println("Enter your choice in 15 seconds :");
Future<Integer> inputFuture = service.submit(callable);
try {
return inputFuture.get(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException("Thread was interrupted", e);
} catch (ExecutionException e) {
throw new IllegalStateException("Something went wrong", e);
} catch (TimeoutException e) {
// tell user they timed out or do something
throw new IllegalStateException("Timed out! Do something here OP!");
} finally {
service.shutdown();
}
}
您可以使用 labelled break(下面给出的代码中的 done:
)和一个 boolean
变量(下面给出的代码中的 valid
)来跟踪输入是否有效。
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getChoiceWithTimeout(10));
}
static int getChoiceWithTimeout(int range) {
Callable<Integer> k = () -> new Scanner(System.in).nextInt();
Long start = System.currentTimeMillis();
int choice = 0;
boolean valid;
ExecutorService l = Executors.newFixedThreadPool(1);
Future<Integer> g;
System.out.println("Enter your choice in 15 seconds :");
g = l.submit(k);
done: while (System.currentTimeMillis() - start < 15 * 1000) {
do {
valid = true;
if (g.isDone()) {
try {
choice = g.get();
if (choice >= 0 && choice <= range) {
break done;
} else {
throw new IllegalArgumentException();
}
} catch (InterruptedException | ExecutionException | IllegalArgumentException e) {
System.out.println("Wrong choice, you have to pick an integer between 0 - " + range);
g = l.submit(k);
valid = false;
}
}
} while (!valid);
}
g.cancel(true);
return choice;
}
}
一个示例 运行: 不要输入任何内容,该方法将在 15 秒后 return 和 0
,就是这样当前正在使用您的代码
Enter your choice in 15 seconds :
0
另一个示例运行: 一旦用户输入有效数字,该方法将return 与输入的值;否则,它将在 15 秒后继续请求有效输入或 return 0
。
Enter your choice in 15 seconds :
a
Wrong choice, you have to pick an integer between 0 - 10
12
Wrong choice, you have to pick an integer between 0 - 10
5
5
注意: 使用标记的 break
不是强制性的,您可以将其替换为传统的 break
ing 方式,但这需要您添加多几行代码。
这是一个简化的较短版本,如果用户没有输入内容,它会在 n 秒后超时:
private static final ExecutorService l = Executors.newFixedThreadPool(1);
private static String getUserInputWithTimeout(int timeout) {
Callable<String> k = () -> new Scanner(System.in).nextLine();
LocalDateTime start = LocalDateTime.now();
Future<String> g = l.submit(k);
while (ChronoUnit.SECONDS.between(start, LocalDateTime.now()) < timeout) {
if (g.isDone()) {
try {
String choice = g.get();
return choice;
} catch (InterruptedException | ExecutionException | IllegalArgumentException e) {
logger.error("ERROR", e);
g = l.submit(k);
}
}
}
logger.info("Timeout...");
g.cancel(true);
return null;
}
public static void main(String[] args) {
logger.info("Input the data in 10 seconds or less...");
String res = getUserInputWithTimeout(10); // 10s until timeout
if(res != null) {
logger.info("user response: [" + res + "]");
}
System.exit(0);
}