概述
Java的NIO,用非阻塞的IO方式,可以用一个线程,处理多个客户端连接(多路复用),就会用到Selector(多路复用器/选择器)。
Selector能够检测多个注册通道channel上是否有事件发生(多个Channel以事件的方式注册多同一个Selector),类似基于epoll的多路复用,如果有事件发生,便获取事件,然后针对每个事件进行相应的处理,这个月就可以用单线程去处理多个连接和请求。
只有在连接/通道真正有读写事件发生时,才会进行读写,就大大减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程。避免多线程之间上下文切换的开销。
说明:
- 当线程从某客户端Socket通道进行读写数据时,若没有数据可用(也就是数据没有准备好),该线程不会阻塞在这里,而是会执行其他任务,直到触发读写完成的事件。
- 线程通常将非阻塞IO的空闲时间用于执行其他通道上的IO操作,所以单个线程可以管理多个输入和输出通道。
- 由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁IO阻塞导致线程挂起。
- 1个IO线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO的一连接一线程模型,架构的性能、弹性伸缩力和可靠性得到极大的提升。
就是Selector会监控注册到它那里的channel,比如有一个如果一直没有事件发生,线程就会空闲着,如果发生了事件,比如OP_ACCEPT事件,Selector就会监控到返回,然后处理,处理完又监控这段时间发生的时间。
对基于epoll的多路复用有所理解的话,理解Selector应该不是难事。
常用API:
//创建并打开一个Selector
public static Selector open()
//查看当前Selector是否处于打开状态
public abstract boolean isOpen();
//获取在该selector上注册的所有SelectionKey集合
public abstract Set<SelectionKey> keys();
//获取在发生了某个事件的SelectionKey集合
public abstract Set<SelectionKey> selectedKeys();
//监控事件发生,这个不会阻塞,会立马返回,返回的是触发事件的个数。可能为0
public abstract int selectNow()
//监控事件发生,如果在timeout期间有一个以上的事件发生,就会返回,或者会阻塞到timeout后返回,返回发生的事件个数。可能为0
public abstract int select(long timeout)
//会一直阻塞,直到有一个以上的事件发生
public abstract int select()
//唤醒,可以唤醒处于select阻塞状态的selector
public abstract Selector wakeup();
//关闭selector
public abstract void close()
版权声明:本文为qq_40837310原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。