标题说的是什么。
如果异步线程在等待Scanner
时被中断并且另一个
IndexOutOfBoundsException
被调用,Java
nextLine()
会抛出 nextLine()
。
这是一些重现问题的代码。
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
/**
* Test class for asynchronous input
*/
public class MainThreaded
{
public static final int SLEEP_MILLIS = 200;
public static final Object LOCK = new Object();
public static boolean breakIfTrueAsynchronous = false;
public static void main (String[] args) {
BlockingQueue<String> inputQueue = new LinkedBlockingDeque<>();
Scanner scanner = new Scanner(System.in);
ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable inputReader = () -> {
while(true) {
String str;
synchronized (scanner) {
str = scanner.nextLine();
}
System.out.println("READ THREAD");
inputQueue.add(str);
}
};
Future<?> task = executor.submit(inputReader);
//run a timer to get the asynchronous error every 3 sec
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (LOCK) {
breakIfTrueAsynchronous = true;
}
}
}, 3000);
System.out.println("Test asynchronous input started, write anything below:");
String input = "";
while(true) { // use ctrl+C to exit
try {
input = inputQueue.poll(SLEEP_MILLIS, TimeUnit.MILLISECONDS);
if(input == null) input = ""; // if timeout elapses, avoid null value
synchronized (LOCK){
if(breakIfTrueAsynchronous){
System.err.println("BREAK RECEIVED");
timer.cancel();
task.cancel(true);
executor.shutdown();
break; // goes to end of main below
}
}
} catch (InterruptedException e) {
System.err.println("INTERRUPT!");
}
if(!input.isEmpty()) {
//use input here
System.out.println("INPUT RECEIVED: " + input);
input = "";
}
}
//this is only executed AFTER breakIfTrueAsynchronous IS TRUE
System.out.println("Task cancelled: " + task.isCancelled());
try{
String str;
synchronized (scanner) {
str = scanner.nextLine();
}
System.out.println("INPUT RECEIVED CORRECTLY: " + str);
}catch (IndexOutOfBoundsException e) {
System.out.println("ERROR. IndexOutOfBoundsException thrown:");
e.printStackTrace();
}
}
}
我希望最后的
scanner.nextLine();
不会抛出任何东西并继续正常阅读System.in
。
相反,我得到了以下 stackTrace:
java.lang.IndexOutOfBoundsException: end at
java.base/java.util.regex.Matcher.region(Matcher.java:1553) at
java.base/java.util.Scanner.findPatternInBuffer(Scanner.java:1097) at
java.base/java.util.Scanner.findWithinHorizon(Scanner.java:1800) at
java.base/java.util.Scanner.nextLine(Scanner.java:1658) at
MainThreaded.main(MainThreaded.java:70)
在
Scanner
上同步解决了异常问题(感谢@user207421),但现在我不明白为什么第一个任务没有被task.cancel(true)
打断。
我现在的工作假设是问题在于线程正在等待时接收到中断
scanner.nextLine()
。
非常感谢任何能解决这个问题的人T.T
我通过仅使用线程进行输入并始终从
BlockingQueue
读取来解决此问题:D 切勿在该单个线程之外调用 scanner.nextLine()
可以防止同步错误,其余的由队列处理。这样我也永远不会停止线程,直到应用程序结束。
非常感谢@rzwitserloot 提供有关可中断方法的所有信息。
我通过仅使用线程读取输入并始终使用
inputQueue.poll()
或inputQueue.take()
来使用代码其他部分的输入解决了这个问题。
永远不要在该单线程之外调用
scanner.nextLine()
可以防止同步错误,其余的由队列处理。这样我也不会停止线程,直到应用程序结束。
需要注意的是,即使在
System.exit()
上,线程也不会停止。 System.exit()
时调用 scanner.nextLine()
会等待输入,然后再关闭线程和应用程序。
非常感谢@rzwitserloot 提供有关可中断方法的所有信息:
包中使用java.*
声明的所有方法都保证是可中断的。throws InterruptedException
不是这些方法之一 - 这意味着它可以或不可中断。取决于操作系统、JVM 版本、供应商、芯片和月相。readLine()
感谢@Nathan 的评论:
中断通过检查标志来工作。代码被阻塞等待 I/O 无法检查标志