使用阻塞 I/O 的 Java 线程池服务器



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

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

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

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

问题:这一切都很好用,但是我不确定我是否使用ThreadPoolExecutor,因为提交的Runnable实例几乎总是阻塞。ThreadPoolExecutor会对此做出反应吗?还是池化线程会简单地阻塞?因为,如果所有池化线程在执行其Runnable时都阻塞,接下来提交一个新的Runnable,那该怎么办?暂停新Runnable?这不好,因为这样新连接的客户端的响应能力将为零,直到某些较旧的客户端断开连接。如果相比之下,线程池选择生成一个新线程来处理Runnable,那么我实际上得到了一个每个客户端的线程方案。

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

提前感谢!

关于ThreadPoolExecutor:这取决于。Executors.newCachedThreadPool()只会为新的 Runnable 创建新线程。另请参阅此问题和接受的答案。但最终会得到每个客户端的线程方案。

Nio防止每个客户端的线程方案(如果有许多客户端发送相对较小的消息,中间有暂停,另请参阅本文(摘要(,我建议不要尝试构建自己的nio克隆。

从头开始

实现nio并不容易,可以在此处找到教程。使用像Netty这样的nio服务器可能更容易。

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

相关内容

  • 没有找到相关文章

最新更新