Java:停止线程TCP服务器的好方法?

时间:2011-04-11 15:28:49

标签: java multithreading concurrent-programming

我有以下TCP客户端 - 服务器通信结构:

  • 在服务器启动服务器上启动 接受线程,接受客户端 连接并传递ServerSocket 它。
  • 当客户端连接到达时, acceptor线程调用accept() ServerSocket并提交客户端 处理工作到工作线程 (通过执行程序/线程池)并为其提供客户端套接字。
  • Worker in循环从中读取数据 客户端套接字流,处理它并发送回复。

问题是如何优雅地停止整个系统?我可以通过关闭ServerSocket来停止接受器线程。它会导致accept()阻塞调用抛出SocketException。但是如何阻止工人呢?他们从流中读取并且此调用正在阻止。根据{{​​3}}流不会抛出InterruptedException,因此worker不能被中断()。

看起来我需要从另一个线程关闭工作套接字,对吧?为此,套接字应该是一个公共字段,或者应该在worker中提供一个方法来关闭它。这会不错?或者可能是我的整个设计存在缺陷?

3 个答案:

答案 0 :(得分:3)

您的模型运作正常。中断IO等不可中断构造的最佳方法是关闭套接字。你当然可以在进入阻塞状态之前处理它,但是如果IO功能没有对中断作出反应你就没有很多好的选择

答案 1 :(得分:2)

我建议使用工作人员定期检查的布尔标志。调用标志shouldStop,如果设置为true,则工作人员清理然后死亡。遵循此方法将允许您实现一些清理代码,这样您就不会遗留资源等等。

答案 2 :(得分:2)

您不能简单地停止服务器。关闭过程可能需要一段时间才能进行清理,因为您需要确保一致性。

想象一下数据库服务器,如果您只是在执行事务时将其关闭,则可能会使其数据不一致。这就是关闭服务器通常需要一段时间的原因。

  • 你必须先停止接受新的 服务器中的连接。
  • 然后你可以等待 目前的工人线程完成 他们的工作然后关闭 服务器和正式关机。
  • 或者你强制工作线程 关闭与他们的联系 客户(可能使用某种方式) 建议的旗帜)。这有可能 意味着要留下一些清理数据 一致的,例如恢复 trasnsactions或任何类型的变化 你已经完成了文件或内存。

根据我的理解,关闭与服务器端客户端的连接应该会导致客户端侧面获得EOF。

<强> [EDIT-1]

我在这个问题上已经深入研究了一下,因为我有一段时间没有使用套接字,因为我发现这个问题很有意思。我认为,正如其他人已经明确指出的那样,唯一的选择是关闭套接字,根据Javadocs会自动关闭输入和输出流/

如果线程没有被IO阻塞,但处于等待状态或休眠状态,我认为仍然建议为给定套接字的相应工作线程发出Thread.interrupt();因为无法确定是否阻止了每个线程的状态。

public static class IOServerWorker implements Runnable{

        private Socket socket;

        public IOServerWorker(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            String line = null;
            try{
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while( (line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }catch(IOException e){
                //TODO: do cleanup here
                //TODO: log | wrap | rethrow exception
            }
        }
    }