举个栗子
/**
* server 端
*/
public class Server {
//在 selector 注册感兴趣的事件
serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
}
private void start() throws Exception{
while(true){
//调用阻塞的select,等待 selector上注册的事件发生
this.selector.select();
//注册读事件(服务端一般不注册 可写事件)
socketChannel.register(selector, SelectionKey.OP_READ);
readBuffer.clear();
socketChannel.read(readBuffer);
readBuffer.flip();
public static void main(String[] args) throws Exception{
new Server().start();
}
创建Selector
通过 Selector.open()方法, 我们可以创建一个选择器:
Selector selector = Selector.open();
1
这里提一下Selector 在Windows和Linux 上有不同的实现
将 Channel 注册到Selector 中
我们需要将 Channel 注册到Selector 中,这样才能通过 Selector 监控 Channel :
//非阻塞模式
channel.configureBlocking(false);
因为 channel 是非阻塞的,因此当没有数据的时候会理解返回,因此 实际上 Selector 是不断的在轮询其注册的 channel 是否有数据就绪。
在使用 Channel.register()方法时, 第二个参数指定了我们对 Channel 的什么类型的事件感兴趣, 这些事件有:
int interestSet = selectionKey.interestOps();
int readySet = selectionKey.readyOps();
selectionKey.attach(theObject);
Object attachedObj = selectionKey.attachment();
1
2
或者在注册时直接附加:
select(long timeout)
select(long timeout),超时阻塞等待timeout毫秒(参数),而不是 select()那样一直阻塞等待,直到有事件就绪。
注意, select()方法返回的值表示有多少个 Channel 可操作.
获取就绪的 Channel(或 事件)
如果 select()方法返回值表示有多个 Channel 准备好了, 那么我们可以通过 Selected key set 访问这个 Channel:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
}
if (key.isConnectable()) {
// a connection was established with a remote server.
}
if (key.isReadable()) {
// a channel is ready for reading
}
if (key.isWritable()) {
// a channel is ready for writing
}
唤醒
选择器执行选择的过程,系统底层会依次询问每个通道是否已经就绪,这个过程可能会造成调用线程进入阻塞状态,wakeup方式可以唤醒在select()方法中阻塞的线程。
selector.wakeup()
1
Selector 整体使用 流程
- 将已经处理过的 key 从 selected keys 集合中删除.
1
2
3
4
5
最后这里附上和前面对应的客户端的代码:
/**
* client 端
*/
public class Client{
private void start()throws IOException {
while (selector.select() > 0 ){
if (key.isReadable()) {
System.out.println("isReadable");
receive(key);
}
System.out.println("receive server message:"+receiveData);
receiveBuffer.clear();
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}