同步单线程模型(BIO)
创建socket和处理请求在一个线程完成。
问题:
- 请求处理慢,后续请求需要等待前面的请求处理完成后才被处理。
- 容易把内核的pending queue打满,造成后续请求自动被系统拒绝。
同步多线程模型(BIO)
派发线程不再独自完成创建socket和处理请求的任务。派发线程接收到一个socket后,马上将socket交给一个工作线程去完成,由工作线程去内核完成socket的读写操作。这种模型下,扛住大几千上万并发不是问题。
问题:
- 由工作线程处理read/write操作,占用工作线程较大的时间。在并发请求达到几万的时候,也会由于创建太多工作线程导致系统资源耗尽。
NIO
NIO最大的不同点是,派发线程不仅仅负责接收socket,还负责管理selector。利用reactor反馈式的模型,等待scoket的数据准备好的时候,才交给工作线程处理。这样工作线程省去了等待socket数据准备的时间,尽可能减少工作线程处理单次请求的时间,减少线程的占用,提高并发。
NIO的优势
Reactor模型+非阻塞(减少线程切换)
reactor模型使得socket数据准备好了之后,才去通知工作线程处理。如果让工作线程自己去等待socket数据准备好了,意味着会让工作线程进入阻塞。而阻塞本质上是增加了现场切换。
内核级别拷贝内存到JVM(减少系统调用)
NIO会在内核创建一块用户态空间可以共享的内存空间,映射到JVM,减少系统调用。
缓冲区增加数据处理的灵活性(clear/flip等操作)
NIO是面向缓存区的,这意味着对数据的操作更加方便灵活。