Java NIO网络编程之Selector

  • Post author:
  • Post category:java




概述

Java的NIO,用非阻塞的IO方式,可以用一个线程,处理多个客户端连接(多路复用),就会用到Selector(多路复用器/选择器)。

Selector能够检测多个注册通道channel上是否有事件发生(多个Channel以事件的方式注册多同一个Selector),类似基于epoll的多路复用,如果有事件发生,便获取事件,然后针对每个事件进行相应的处理,这个月就可以用单线程去处理多个连接和请求。

只有在连接/通道真正有读写事件发生时,才会进行读写,就大大减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程。避免多线程之间上下文切换的开销。

在这里插入图片描述

说明:

  1. 当线程从某客户端Socket通道进行读写数据时,若没有数据可用(也就是数据没有准备好),该线程不会阻塞在这里,而是会执行其他任务,直到触发读写完成的事件。
  2. 线程通常将非阻塞IO的空闲时间用于执行其他通道上的IO操作,所以单个线程可以管理多个输入和输出通道。
  3. 由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁IO阻塞导致线程挂起。
  4. 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 版权协议,转载请附上原文出处链接和本声明。