Java非阻塞IO NIO之Selector选择器

NIO自从JDK1.4版本以来就添加的一个非阻塞I/O框架,NIO是Java为解决网络通讯中高并发问题的一个类库,Selector是java NIO的一个组件,用于检查一个或多个NIO Channel的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接,所以Selecotr是实现了多路复用的关键。

为什么要使用Selector呢?

用单线程处理多个channels的好处是我需要更少的线程来处理channel。实际上,你甚至可以用一个线程来处理所有的channels。从操作系统的角度来看,切换线程开销是比较昂贵的,并且每个线程都需要占用系统资源,因此使用的线程自然是越少越好。

需要留意的是,现代操作系统和CPU在多任务处理上已经变得越来越好,所以多线程带来的影响也越来越小。如果一个CPU是多核的,如果不执行多任务反而是浪费了机器的性能。不过这些设计讨论是另外的话题了。简而言之,通过Selector我们可以实现单线程操作多个channel。

这有一幅示意图,描述了单线程处理三个channel的情况:

 

Java非阻塞IO NIO之Selector选择器_第1张图片

图一

从图中我们可以看到,一个线程通过使用Selector可以同时管理3个Channel,那么如何实现这种管理的呢?我们先来看看Selector的定义:选择器(Selector)是SelectableChannle 对象的多路复用器,Selector 可以同时监控多个SelectableChannel 的IO 状况。不同于BIO(阻塞式I/O),Selector通过将channel注册到相应的集合中,在注册时使用一个SelectionKey来表示当前channel的状态,从而实现管理多个channel

 

创建一个selector的方法:

Selector selector=Selector.open();//创建一个Selector是通过Selector提供的open方法实现的。

注册Channel到Selector上,使得Selector可以管理Channel

channel.configureBlocking(false);  //将阻塞设置为非阻塞

SelectionKey key = channel.register(selector, SelectionKey.OP_READ); 

第一句代码是将channel转换为非阻塞模式,这一句是必不可少的,第二句代码在的使用方法是将一个chanel注册到一个selector中,在编写代码是应该注意一下,这个时候我们能够发现第二个参数SelectionKey.OP_READ,这个表示了当前channel的状态,我们来看看SelectionKey提供的其他几种状态:

1.Connect   //此时处于“连接就绪”状态

2.Accept   //此时处于“可连接就绪”状态

3.Read      //此时处于“读就绪”状态

4.Write     //此时处于“写就绪”状态

这四种状态是用来表示channel的,在SelctionKey中他们分别对应:

1.SelectionKey.OP_CONNECT

2.SelectionKey.OP_ACCEPT

3.SelectionKey.OP_READ

4.SelectionKey.OP_WRITE

若注册时不止监听一个事件,则可以使用“位或”操作符连接。

public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;

只写出8位,其余的位置不写出来,大家知道int有32位就行
0000 0001   向左移0位后  0000 0001
0000 0001   向左移2位后  0000 0100
0000 0001   向左移3位后  0000 1000
0000 0001   向左移4位后  0001 0000

然后在对应位上为1表示监听对应事件,所以有:
OP_READ|OP_WRITE =0000 0001 | 0000 0100 
结果为:0000 0101,在第6位和第8位上为1,表示监听两种事件


注:这种方式也可以用来实现权限管理哦!

channel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

 

Java非阻塞IO NIO之Selector选择器_第2张图片

图二

看完了SelectionKey对象,我们再回过头来看看我们的Selector类,类中一个方法keys(),该方法返回的是一个SelectionKey类型的Set集合,该方法能够将所有状态为OP_CONNECT的SelectionKey集合,也就是返回所有接入Selector的channel,我们可以通过SelectionKey中的channel方法获得到Channel对象,这样的话,我们就获得了Seelectoe管理的所有Channel对象。有了这个对象我们自然可以完成很多东西,关于这方面的应用我就不多叙述了。

Selector提供了一个select()方法,该方法返回所有可用的channel数量。

Selector还提供了selectedKeys()方法,用于获得所有可用的channel。

关于其他方法大家有兴趣可以看JDK的源码进行深一步的了解。

参考文章:http://tutorials.jenkov.com/java-nio/selectors.html

你可能感兴趣的:(java)