What title says.
Java Scanner throws IndexOutOfBoundsException if an asynchronous thread is interruped while waiting on nextLine() and another nextLine() is called.
Here is some code that reproduces the problem.
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) {
try {
String str = scanner.nextLine();
inputQueue.add(str);
}catch (NoSuchElementException ignored){}
//NoSuchElement triggered on ctrl+c
}
};
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) {
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 ignored) {
System.err.println("ERROR OF READER!");
}
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 = scanner.nextLine();
System.out.println("INPUT RECEIVED CORRECTLY: " + str);
}catch (IndexOutOfBoundsException e) {
System.out.println("ERROR. IndexOutOfBoundsException thrown:");
e.printStackTrace();
}
}
}
I would expect the final scanner.nextLine(); to not throw anything and keep reading System.in as normal.
Instead I got the following 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)
Alessandro K Ruzza is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.