【发布时间】: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