我已经看到很多主题将较旧的Java io模型与较新的java nio模型进行比较,前者是同步/阻塞,后者是异步/非阻塞。因为nio是非阻塞的,所以当需要同时处理大量并发连接而不分配由于上下文切换/内存使用而无法很好扩展的大量线程时,它比java io更合适。
我对这个论点的问题是IO与NIO的比较总是给出每个连接使用一个线程的IO的例子。使用java IO的开发人员是否可以简单地分配有限数量的线程(线程池)来阻止IO操作(即文件读取或数据库查询)并对它们进行排队?让我们说我正在使用java的ServerSocket类从头开始创建一个http服务器。假设我收到客户端的请求,要求我进行数据库查询,这是由于JDBC规范而导致的阻塞操作。难道我不能简单地将数据库查询排队到ThreadPool,并在池完成处理时将作业的回调交给它吗?当然,我分配线程来处理io-bounds请求,但线程的数量是有限的。由于IO操作通常是同步的(在某种程度上),尝试为每个db查询分配一个线程,或者每个文件的读/写线程都是没有意义的。
通过这种方式,您可以获得线程和异步编程的好处,而不会分配太多的线程。
我在这个模型中看到的唯一弱点是,如果所有io-bound操作都被卡住(可能是由于编程错误),将来的排队请求将被暂停,直到它们被解除或超时。主逻辑仍然是并发的,但IO不是。
所以,问题:NIO是否解决了上述模型无法解决的任何问题(除了我刚才提到的潜在弱点)?
答案 0 :(得分:3)
当然,您可以使用池和有限数量的线程执行此操作并处理您自己的I / O,但您基本上会复制NIO为您提供的内容,但无法利用原生API。
您的系统无法正常处理的问题之一是,有数千个套接字处理服务器推送,BitTorrent客户端或非常繁忙的内容服务器所需的慢I / O.
更传统的请求/响应系统可以很好地与您的解决方案一起工作,但是再次,它们也可以在每个请求的线程中正常工作,因为通常遇到的第一个瓶颈是CPU或内存消耗。
答案 1 :(得分:1)
如果使用您所描述的模型创建具有N个线程的Web服务器,则恶意行为者可以打开N个连接并且不发送任何数据。现在您的服务器完全被锁定,无法完成有意义的工作。 NIO带来的选择器是允许您一次等待 多个 连接的选择器。使用此原语,您可以创建一个线程来等待 all 当前连接。没有任何一个连接可以占用整个线程的执行状态,因为您只将该作业提供给单个线程。系统上的所有其他线程现在可以根据需要处理传入的数据。
即使假设正常的非恶意行为者,单线程/阻塞调用模型也可能会崩溃。您确定IO操作可能会卡住,并且可能导致系统出现故障。但是,某些客户端(比如聊天会话中的持久客户端)可能会长时间闲置。对服务器的所有请求都不一定是即时和完整的。