您的位置:首页 > 编程语言 > Java开发

jdk源码分析 ——Selector深入分析

2018-01-20 15:46 316 查看
1、spi方式的selector定制化

selector通过SelectorProvider创建的,通常不同安装版本的jdk中已经封装了相应的Select和SelectorProvider了,通过spi的方式进行扩展。(PS:spi是一种jdk提供的低侵入方式的扩展实现,目前已经在大多数的框架中使用了,类似dubbo框架也使用该方式,让用户进行更好的定制化实现)

2、selector的原理

NIO极大提高了IO的并发,且在各大操作系统都已经有了相应的支持,类似linux的select、pool、epoll等,windows的IOCP等。在NIO中又包含了两种机制,一种是reactor;另外一种是proactor,这两种方式的主要区别是:IO数据是自己去内核读取,还是提供用户空间数据缓冲区,让内核读取。

在目前的jdk版本中也最大化的利用了操作系统的NIO机制,封装成了统一的接口供java应用使用,该实现机制是在操作系统的NIO的reactor或者proactor机制之上,再次封装了一次,并创建相应的socket事件的映射即可。

3、selector多线程特性

在jdk中自带的selector的方法是线程安全的,可以多线程调用selector的方法,但是从我个人的实践来看,其实没有必要多线程调用,其实单个线程就可以了,最主要是select出来的Set这个可以进行多线程的处理,但是该集合是非线程安全的,所以在多线程使用的时候需要进行同步的操作

4、关于多线程accept的理解

为什么需要多线程的accept?这个问题需要仔细的分析,目前很多框架都是用了多线程的accept,但是使用多线程的accept是有条件的,那就是在某一个线程accept之后之后,会对新的socket进行一些简单的认证的操作等,操作完了之后再把该socket放入业务线程池。由于这些操作需要花费一定的时间,所以这个时候可以把serversocket让出来,让其他的线程accept。

那么问题来了:那为什么不可以单个线程accept,然后将accept的socket直接丢到业务线程池呢?

其实这样也是可以的,但是为了更好的符合单一职责的原则,业务线程池应该是主要负责业务处理的,那么像socket的一些合法性检测等操作应该使用单独的线程池进行,既然有了独立的线程池,而且这些检测本身也不是特别耗时,所以就可以把accept也放到该线程中了。

但是在很早之前的操作系统中这种多线程的accept会出现“惊群”效应,目前很多操作系统已经解决了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jdk socket select