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

时间:2014-05-30 12:07:26

标签: java networking threadpool

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

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

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

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

问题:这一切都很有效,但我不确定我对take的使用,因为提交的ThreadPoolExecutor个实例几乎总是阻止。 Runnable会对此作出反应吗?或者汇集的线程会阻塞?因为,如果所有池化线程在执行ThreadPoolExecutor和接下来的Runnable时全部阻塞,则会提交新的Runnable,然后呢?暂停新的Runnable?这并不好,因为新连接的客户端将具有零响应,直到一些旧客户端断开连接。相反,如果线程池选择生成一个新线程来处理Runnable,那么我实际上得到了一个每个客户端的线程场景。

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

提前致谢!

1 个答案:

答案 0 :(得分:1)

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

Nio阻止了每个客户端的线程场景(如果有很多客户端发送相对较小的消息,中间有暂停,请参阅({3}}的摘要),我建议不要尝试建立自己的nio克隆。

从头开始实施nio并不容易,可以找到一个教程this article。使用herenio服务器可能会更容易。

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