当多个线程在Java中使用System.in上的扫描仪时,stdin数据会怎样?
作者:互联网
假设我有一个主程序,该程序在stdin上侦听命令行参数.这个主程序产生一个线程来做一些事情,并且该线程还需要监听stdin.
如果两个不同的线程在System.in上都装有Scanners,一个线程是否阻塞了另一个线程,还是两个线程都从stdin接收了所有数据?
解决方法:
我尝试了以下代码(在main方法中):
Scanner scan = new Scanner(System.in);
new Thread(){
public void run(){
Scanner scan = new Scanner(System.in);
while(true){
if(scan.hasNext())System.out.println("Thread:"+scan.nextLine());
}
}
}.start();
while(true){
if(scan.hasNext())System.out.println("Main:"+scan.nextLine());
}
在大多数情况下,两个线程都不在打印,并且在打印时,很显然它们都在同时解析输入.尽管它们并没有以重复的字符结尾(但我认为),但是输入abcd可能会将ac发送到一个线程的扫描程序,将bd发送给另一个线程.
样例运行(任何未输入Main:或Thread:的输入):
abcdefghi
jklmnopqr
Thread:ghi
Thread:mnopqr
stuvwxyzA
Thread:vwxyzA
BCDEFGHIJ
KLMNOPQRS
Thread:KLM
Main:abcdefjklstuBCDEFGHIJ
TUVWXYZ`~
1!2@3#4$5
Main:NOPQRS~
Thread:TUVWXYZ`1!2@3#4$5
如果您希望两个线程都获取标准输入,则可以创建一个这样的类(它可以工作,但根本不是最佳选择):
class STDIN extends Thread{ //this way, it can only be used once, like intended.
private static final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
private static final ArrayList<Integer> data = new ArrayList<>();
private static final ArrayList<Integer> dataFlags = new ArrayList<>();
public void run(){
while(true){
synchronized(data){
try {
int i = stdin.read();
if (i == -1) break;
data.add(i);
} catch (IOException ex) {
ex.printStackTrace();
}
synchronized(dataFlags){
if (dataFlags.get(0) == 3){
dataFlags.remove(0);
data.remove(0);
}
}
}
}
try {
stdin.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public int getByte(int index){
synchronized(data){
return data.get(index);
}
}
public void flagA(int index){
synchronized(dataFlags){
if (index>dataFlags.size()){
dataFlags.add(1);
}
else{
dataFlags.set(index, dataFlags.get(index) | 1);
}
}
}
public void flagB(int index){
synchronized(dataFlags){
if (index>dataFlags.size()){
dataFlags.add(2);
}
else{
dataFlags.set(index, dataFlags.get(index) | 2);
}
}
}
}
使用它,您可以读取数据,但一次只能读取一个字符.完成数据处理后,您可以根据所处的线程对其进行标记. (一个线程的flagA,另一个线程的flagB).
这是Scanner的部分包装.我只包括nextLine方法:
class MultithreadedScanner {
private final Scanner scan;
private final ArrayList<MultithreadedScannerListener> toNotify;
public MultithreadedScanner(InputStream is) {
scan = new Scanner(is);
toNotify = new ArrayList<>();
}
public void addMultithreadedScannerListener(MultithreadedScannerListener l) {
synchronized (toNotify) {
toNotify.add(l);
}
}
public void nextLine() {
String s = scan.nextLine();
synchronized(toNotify){
for (MultithreadedScannerListener l: toNotify){
l.receiveNextLine(s);
}
}
}
}
interface MultithreadedScannerListener {
public void receiveNextLine(String line);
}
使每个要在实现MultithreadedScannerListener上监听标准输入的线程,并将它们添加到MultithreadedScanner.需要新信息时,请致电nextLine;建议仅从一个线程执行此操作.
标签:java-util-scanner,multithreading,user-input,blocking,java 来源: https://codeday.me/bug/20191030/1964186.html