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

标签 java networking threadpool

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

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

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

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

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

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

提前致谢!

最佳答案

关于 ThreadPoolExecutor:视情况而定。 Executors.newCachedThreadPool() 只会为新的 Runnable 创建新的线程。另见 this question和接受的答案。但是您最终会遇到每个客户端一个线程的情况。

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

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

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

关于使用阻塞 I/O 的 Java 线程池服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23954253/

相关文章:

java - 无效或损坏的 jarFile

java - 在自定义工具箱的 Matlab Simulink block 内存储自定义 java 对象

c++ - .NET 从具有 www 接口(interface)的打印机获取数据

java - findInLine 错误仅搜索第一行

java - 轴2 : XmlSchema class not found

wordpress - Docker 将 wordpress 从 HTTP 更改为 HTTPS

c++ - pthread_mutex_lock错误

c# - ThreadPool.QueueUserWorkItem——是否需要新的 WaitCallback()?

Java - 如何记录线程池中的指标?

c# - .NET 中是否可以对 Threadpool 中的任务进行优先级排序?