【问题标题】:How to handle different scanner in different threads如何在不同的线程中处理不同的扫描仪
【发布时间】:2019-01-12 12:03:32
【问题描述】:

为了避免 XY 问题,我将解释上下文: 我正在控制台模式下做一个聊天应用程序。用户可以发送文本或文件。如果用户收到一个文件,控制台会打印“收到新文件!你想把它保存在哪里?:”。

现在的问题: 我的Main.java 中有一个while(true) 循环,我在其中询问用户他想做什么,例如“发送”以发送消息,或“会话”以打印与用户的对话。所以这个循环中有一个scanner.nextLine()

我有一个线程listener.java 监听TCP 连接,当我在TCP 中接收到一个文件时,我想执行scanner.nextLine() 来询问用户“你想把它保存在哪里?”。 但我不能这样做,因为我的listener.java 和我的Main.java 干扰,两个扫描仪试图同时从同一流( System.in ) 收听。

我尝试了Multiple Scanners in Multiple Threads 此处指出的解决方案,但它不起作用。 我试图同步扫描仪,但似乎我的线程没有成功锁定扫描仪。 与可重入锁相同的结果...

我写了一段代码让你明白我在说什么,这不是我的实际代码,但它重现了我的问题,一个线程与 Main 同时执行 sc.nextLine()。

public static void main(String [] args) throws IOException, InterruptedException {
    Scanner sc = new Scanner(System.in);

    Thread tt = new Thread(new Runnable() {
        @Override
        public void run() {

            try {
                //The thread wait...
                Thread.currentThread().sleep(2000);
            } catch (InterruptedException e) {
            }

            String test= "";
            //Here i receive a file so i ask the user where he wants to save it...
            synchronized (sc) {
                System.out.print("New file received ! where do you want to save it ? ");
                test = sc.nextLine();
            }
            System.out.println("File written : " + test);
        }
    });
    tt.start();

    System.out.print("Main blabla ? ");
    String bb = "";
    while(true) {
        synchronized (sc) {
            bb = sc.nextLine();

        }
        System.out.print("blabla : " + bb);
        //Do actions.....
    }
}

【问题讨论】:

  • 从一个线程调用方法通知另一个,获取控制扫描仪打印的线程。您可以简单地使用阻塞逻辑或更复杂的异步逻辑来做到这一点。绝对不要尝试共享输入流 - 您很快就会遇到缓冲区问题。
  • 但是“同步”关键字的目的不就是允许多个线程访问一个资源吗?我的意思是,这是为了它的设计,不是吗?为什么它在这种情况下不起作用?感谢您的回答
  • 首先,no-synchronized是为了保证对共享资源的同步访问;明确禁止并发访问。但它不起作用的真正原因是Scanner 缓冲。没有多少神奇的语言关键字可以为您解决这个问题。

标签: java multithreading java.util.scanner bufferedreader synchronized


【解决方案1】:

使用多个Scanners 从单个流中读取感觉很脆弱。应用程序将受益于封装用户交互功能的方式,流和扫描仪不能被代码库的其他部分直接访问。抽象应该既实现命令循环,又处理从外部传入的事件,例如接收文件。

接收事件需要适当地同步并理想地缓冲到队列中,以便在用户响应先前事件时可以接收新事件。总而言之,用户交互抽象总是只做一件事——如果没有事件,则读取用户对下一个事件或下一个命令的响应。这是,将有一个单独的线程和Scanner 专用于读取输入流。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多