如何正确停止等待stdIn输入的线程?

时间:2018-02-04 01:18:11

标签: java multithreading concurrency

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

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

这些是用于实现此目的的代码:

主线程:

    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());
    }

第二个线程的Runnable:

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()上,这会中断线程,直到用户发送另一条消息即使他已经断线了。

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

如果有人想阅读完整的代码,可以在此github page中找到。

2 个答案:

答案 0 :(得分:2)

@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之前检查它是否" bye"然后调用中断

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

//member variable 
 private static volatile boolean isRunning = true;

public static void shutdown()
    {
        running = false;
    }

    public void run()
    {
        while( running )
        {
            //do whatever.
        }

答案 1 :(得分:1)

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

article有详细说明。