【问题标题】:Java thread pooled server using blocking I/O使用阻塞 I/O 的 Java 线程池服务器
【发布时间】:2014-07-20 04:38:18
【问题描述】:

我已经用 Java 实现了一个服务器,在从某个客户端接收数据后,它只是将数据转发给所有其他客户端(包括发送者)。我对我的 OO 设计感到满意,我将所有套接字包装在提供“回调”的类中。当一些数据准备好时(或当套接字关闭时)调用它们——使用这种设计,我可以轻松地实现一个简单的 TLV 协议来自动发送数据包:在收到完整的数据包之前不会调用回调。

现在,我使用 java.io 包阻止对套接字流的 I/O 调用(并通过这些回调使它们看起来“异步”)。所以我在我的套接字包装类中使用线程:当打开一个套接字时,该函数返回一个Runnable 实现,在运行时,将对InputStream 进行阻塞调用,缓冲数据并最终调用回调。

=> 在客户端应用程序中,我只是在 Thread 实例中启动此 Runnable,因为它只是一个线程。

=> 在我的服务器中,我将在创建新套接字(即接受新客户端时)时获得的所有Runnable 实现提交到ThreadPoolExecutor。 (仅供参考:套接字的回调只是put 在BlockingQueue 中接收到的数据包。一个单独的(非池化)“调度程序”Thread 实例不断takes 来自该队列的数据包并写入它们到当前连接到服务器的所有套接字。)

问题:这一切都很好,但是我不确定我是否使用ThreadPoolExecutor,因为提交的Runnable 实例几乎总是阻塞。 ThreadPoolExecutor 会对此做出反应吗?或者池中的线程会简单地阻塞吗?因为,如果所有池化线程在执行它们的Runnable 时都处于阻塞状态,接下来会提交一个新的Runnable,那会怎样?暂停新的Runnable?这不好,因为新连接的客户端将具有零响应,直到一些旧客户端断开连接。相反,如果线程池选择生成一个新线程来处理Runnable,那么我实际上会得到一个线程每个客户端的场景。

我希望线程池“抢占”阻塞线程并使用它们来处理其他套接字,例如挂起 I/O 绑定进程并且在其 I/O 完成之前不会再次调度它们的操作系统。这完全有可能吗,还是我必须使用nio 重写所有内容才能做到这一点? (如果需要nio,你能指出我应该从哪里开始阅读吗?)

提前致谢!

【问题讨论】:

    标签: java networking threadpool


    【解决方案1】:

    关于ThreadPoolExecutor:这取决于。 Executors.newCachedThreadPool() 只会为新的 Runnables 创建新线程。另请参阅this question 和接受的答案。但是您最终会遇到一个每个客户端线程的场景。

    Nio 防止线程每个客户端的情况(如果有许多客户端发送相对较小的消息并在其间暂停,另请参阅(摘要)this article),我建议不要尝试构建自己的@ 987654330@克隆。

    从头开始实施nio 并不容易,可以在here 找到教程。使用像Netty 这样的nio 服务器可能更容易。

    另一种选择是使用旨在处理许多发送和接收小消息的客户端的技术。学习和设置需要一些时间,但我设法让Tomcat WebSockets 服务器很快与Jetty WebSocket 客户端通信。使用这项技术的重写可能会减少工作量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多