编程语言
首页 > 编程语言> > 当多个线程在Java中使用System.in上的扫描仪时,stdin数据会怎样?

当多个线程在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