Servlet API和NIO: 最终组合在一起 - 编程入门网
zed Object remove()
{
if ( isEmpty() ) {
try { waitingThreads++; wait();}
catch (InterruptedException e) {Thread.interrupted();}
waitingThreads--;
}
return removeFirst();
}
public boolean isEmpty() {
return (size() - waitingThreads <= 0);
}
}
工作线程的数量与 Web 客户机的数量无关。不是为每个打开的 socket 分配一个线程,相反,我们把所有请求放到一个由一组 RequestHandlerThread 实例所服务的通用队列中。理想情况下,线程的数量应该根据处理器的数量和请求的长度或持续时间进行调整。如果请求通过资源或处理需求花了很长时间,那么通过添加更多的线程,可以提高感知到的服务质量。 注意,这不一定提高整体的吞吐量,但确实改善了用户体验。即使在超载的情况下,也会给每个线程一个处理时间片。这一原则同样适用于基于标准 Java I/O 的服务器;不过这些服务器是受到限制的,因为会 要求 它们为每个打开的 socket 连接分配一个线程。NIO 服务器完全不用担心这一点,因此它们可以扩展到大量用户。最后的结果是 NIO 服务器仍然需要线程,只是不需要那么多。 Servlet API和NIO: 最终组合在一起(3)时间:2011-01-26 IBM Taylor Cowan请求处理 Client 类有两个用途。首先,通过把传入的非阻塞 I/O 转换成可由 Servlet API 消费的阻塞 InputStream ,它解决了阻塞/非阻塞问题。其次,它管理特定客户机的请求状态。因为当全部读取消息时,非阻塞通道没有给出任何提示,所以强制我们在协议层处理这一情况。Client 类在任意指定的时刻都指出了它是否正在参与进行中的请求。如果它准备处理新请求, write() 方法就会为请求处理而将该客户机排到队列中。如果它已经参与了请求,它就只是使用 PipedInputStream 和 PipedOutputStream 类把传入的字节转换成一个 InputStream 。 图 1 展示了两个线程围绕管道进行交互。主线程把从通道读取的数据写到管道中。管道把相同的数据作为 InputStream 提供给消费者。管道的另一个重要特性是:它是进行缓冲处理的。如果没有进行缓冲处理,主线程在尝试写到管道时就会阻塞。因为主线程单独负责所有客户机间的多路复用,因此我们不能让它阻塞。 图 1. PipedInput/OutputStream 在 Client 自己排队后,工作线程就可以消费它了。RequestHandlerThread 类承担了这个角色。至此,我们已经看到主线程是如何连续地循环的,它要么接受新客户机,要么读取新的 I/O。工作线程循环等待新请求。当客户机在请求队列上变为可用时,它就马上被 remove() 方法中阻塞的第一个等待线程所消费。 清单 3. RequestHandlerThread.java
然后该线程创建新的 HttpRequest 和 HttpResponse 实例,并调用 defaultServlet 的 service 方法。注意, HttpRequest 是用 Client 对象的 clientInputStream 属性构造的。PipedInputStream 就是负责把非阻塞 I/O 转换成阻塞流。 从现在开始,请求处理就与您在 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |