使用阻塞I/O的Java线程池服务器
我用Java实现了一个服务器,在从某个客户端接收数据时,它只需将数据转发给所有其他客户端(包括发送方)。我对我的OO设计很满意,我将所有套接字封装在提供“回调”的类中。当一些数据准备就绪(或套接字关闭)时调用它们——使用这种设计,我可以轻松实现一个简单的TLV协议来自动发送数据包:在收到完整数据包之前不会调用回调 现在,我使用使用阻塞I/O的Java线程池服务器,java,networking,threadpool,Java,Networking,Threadpool,我用Java实现了一个服务器,在从某个客户端接收数据时,它只需将数据转发给所有其他客户端(包括发送方)。我对我的OO设计很满意,我将所有套接字封装在提供“回调”的类中。当一些数据准备就绪(或套接字关闭)时调用它们——使用这种设计,我可以轻松实现一个简单的TLV协议来自动发送数据包:在收到完整数据包之前不会调用回调 现在,我使用java.io包阻止对套接字流的I/O调用(并通过这些回调使它们看起来“异步”)。因此,我在套接字包装类中使用线程:当打开套接字时,该函数返回一个Runnable实现,该实
java.io
包阻止对套接字流的I/O调用(并通过这些回调使它们看起来“异步”)。因此,我在套接字包装类中使用线程:当打开套接字时,该函数返回一个Runnable
实现,该实现在运行时将对InputStream
执行阻塞调用,缓冲数据并最终调用回调
=>在客户端应用程序中,我只需在线程
实例中启动这个可运行
,因为它只是一个线程
=>在我的服务器中,我将创建新套接字(即接受新客户端时)得到的所有Runnable
实现提交到ThreadPoolExecutor
中。(仅供参考:套接字的回调只是将接收到的数据包放入一个阻塞队列中。一个单独的(非池化的)“dispatcher”线程实例持续从该队列中取下数据包,并将其写入当前连接到服务器的所有套接字。)
问题:这一切都很好,但是我不确定我是否使用了ThreadPoolExecutor
,因为提交的Runnable
实例几乎总是阻塞的。ThreadPoolExecutor
会对此做出反应吗?还是池线程只是阻塞?因为,如果所有池线程都在执行其Runnable
时阻塞,然后提交一个新的Runnable
,然后呢?挂起新的可运行
?这是不好的,因为这样新连接的客户端将没有响应,直到一些旧客户端断开连接。相比之下,如果线程池选择生成一个新线程来处理可运行的
,那么实际上每个客户端都会得到一个线程
我希望线程池“抢占”阻塞线程,并使用它们处理其他套接字,就像操作系统暂停I/O绑定的进程,在I/O完成之前不会再次调度它们。这是可能的,还是我必须使用nio
重写所有内容才能做到这一点?(如果需要nio
,你能指出我应该从哪里开始阅读吗?)
提前谢谢 关于ThreadPoolExecutor
:视情况而定。一个Executors.newCachedThreadPool()
只会为新的可运行程序创建新线程。另请参见和接受的答案。但是,您最终将得到每个客户端一个线程的场景
Nio
防止每个客户端都有线程的情况(如果有许多客户端发送相对较小的消息,其间有停顿,请参见(的摘要)),我建议不要尝试构建自己的Nio
克隆
从头开始实施nio
并不容易,可以找到一个教程。像这样使用nio
服务器可能更容易
另一种选择是使用一种设计用于处理发送和接收小消息的许多客户端的技术。学习和设置需要一些时间,但我设法让服务器很快地与客户机对话。使用这种技术进行重写可能会减少工作量