【问题标题】:How to correctly stop a thread that is waiting for input from stdIn?如何正确停止等待 stdIn 输入的线程?
【发布时间】:2018-02-04 01:18:11
【问题描述】:

我已经实现了一个简单的聊天应用程序,它接收消息并将它们重定向给所有用户,因为我正在学习并行编程。

客户端有两个线程:一个用于监听服务器,另一个(主线程)用于写入服务器。

这些是用来实现这个的代码:

主线程:

    try {
        Thread listener = new Thread(new Receiver(in));
        listener.start();
        while (listener.isAlive()) {
            out.println(stdIn.readLine());
        }
        out.close();
        in.close();
        clientSocket.close();
    } catch (IOException e) {
        System.err.println("Error trying to send text to server" + e.getMessage());
    }

第二个线程可运行:

public class Receiver implements Runnable {

    private BufferedReader in;

    public Receiver(BufferedReader serverInput) {
        this.in = serverInput;
    }

    @Override
    public void run() {
        String responseLine;
        try {
            while ((responseLine = in.readLine()) != null) {
                System.out.println(responseLine);

                if (responseLine.contains("Bye")) break;
            }
        } catch (IOException e) {
                System.err.println("Erro ao receber mensagem do servidor: " + e.getMessage());
        }
    }
}

客户端应该发送一条消息 (#quit) 以退出聊天,服务器将回复一条消息 (Bye) 以完成客户端应用程序。

接收线程停止生命周期后如何停止主线程?

我使用isAlive() 方法来完成它,但是在用户发送#quit 消息后,线程仍然处于活动状态,它再次落在stdIn.readline() 上,这会中断线程直到用户发送另一条消息,即使他已经断开连接。

我尝试实现另一个线程(称为发件人)向服务器发送消息,并在主线程上使用listener.join()Thread.interrupt() 中断发件人线程,但发件人线程仍然落在stdIn.readline() 方法和我不知道如何正确中断 IO。

如果有人想阅读完整的代码,请访问github page

【问题讨论】:

    标签: java multithreading concurrency


    【解决方案1】:
    @Override
    public void run() {
        String responseLine;
        try {
            while(!isInterrupted()) 
            while ((responseLine = in.readLine()) != null) {
                System.out.println(responseLine);
    
                if (responseLine.contains("Bye")) break;
            }
        } catch (IOException e) {
                System.err.println("Erro ao receber mensagem do servidor: " + e.getMessage());
        }
    }
    

    从另一个线程,调用该线程上的interrupt() 以将其关闭

    例如,在打印 stdInput 之前检查它是否“再见”然后调用中断


    您也可以使用isRunning 之类的标志并调用方法shutdown()

    //member variable 
     private static volatile boolean isRunning = true;
    
    public static void shutdown()
        {
            running = false;
        }
    
        public void run()
        {
            while( running )
            {
                //do whatever.
            }
    

    【讨论】:

    • 感谢您的回答。我已经尝试从另一个线程调用interrupt() 方法,但是即使在调用中断之后主线程仍然等待readline() 上的输入。基本上发生的事情是用户在退出之前仍然需要发送最后一条无用的消息。标志解决方案在Thread.sleep() 的帮助下工作,它会一直休眠直到服务器响应,如果线程被中断则抛出异常。但我想这很容易出错。
    【解决方案2】:

    没有简单的解决方案,因为从流中读取是一个阻塞操作,我看到在 EHCache/Terracotta 中实现的一个技巧是使用 2 个线程而不是 1 个线程,一个线程将从流中进行实际读取(可调用),而另一个线程将设置一个执行器服务并提交第一个线程(任务)(使用Future)。

    这个article有详细的描述。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-22
      • 2012-07-22
      • 1970-01-01
      • 2019-08-09
      • 1970-01-01
      • 2014-07-09
      相关资源
      最近更新 更多