在Java NIO中,选择器(Selector)是可选择通道的多路复用器,可用作可以进入非阻塞模式的特殊类型的通道。它可以检查一个或多个NIO通道,并确定哪个通道准备好了可以进行通信,即读取或写入。
选择器的用途是什么?
选择器(Selector)用于使用单个线程处理多个通道。 因此,它需要较少的线程来处理这些通道。 线程之间的切换对于操作系统来说是昂贵的。 因此,使用它可以提高系统效率。
下面来看看使用选择器来处理3
个通道的线程的示意图:
下面是聚集原理的简单说明:
创建选择器
可以通过调用Selector.open()
方法创建一个选择器,如下代码所示:
Selector selector = Selector.open();
打开服务器套接字通道
下面来看看打开服务器套接字通道的例子:
ServerSocketChannel serverSocket = ServerSocketChannel.open();
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 8099);
serverSocket.bind(hostAddress);
使用选择器选择通道
在使用选择器注册一个或多个通道时,可以调用select()
方法之一。 该方法返回一个准备好进行要执行事件的通道,即:连接,读取,写入或接受。
可用于选择通道的各种select()
方法有:
int select()
:由select()
方法返回的整数值通知有多少个通道准备好进行通信。int select(long TS)
:方法与select()
相同,除了阻塞最大TS(毫秒)时间的输出。int selectNow()
:它不阻止输出并立即返回任何准备好的通道。selectedKeys()
- 当调用了任何一个select()
方法后,它将返回一个值,表示一个或多个通道准备就绪,那么我们可以通过使用选择的键集合来访问就绪通道,通过调用选择器selectedkeys()
方法如下:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
可以迭代所选的键集合来访问准备好的信道,如下所示:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if(key.isConnectable()) {
// The connection was established with a remote server.
} else if (key.isAcceptable()) {
// The connection was accepted by a ServerSocketChannel.
} else if (key.isWritable()) {
// The channel is ready for writing
} else if (key.isReadable()) {
// The channel is ready for reading
}
keyIterator.remove();
}
上述循环迭代所选择的键集合中的键,以确定使用所选通道执行的操作。
完整的选择循环示意图如下所示:
基本选择器示例
主程序:
package com.yiibai;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.Set;
import java.util.Iterator;
import java.net.InetSocketAddress;
public class SelectorExample {
public static void main(String[] args) throws IOException {
// Get the selector
Selector selector = Selector.open();
System.out.println("Selector is open for making connection: " + selector.isOpen());
// Get the server socket channel and register using selector
ServerSocketChannel SS = ServerSocketChannel.open();
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 8080);
SS.bind(hostAddress);
SS.configureBlocking(false);
int ops = SS.validOps();
SelectionKey selectKy = SS.register(selector, ops, null);
for (;;) {
System.out.println("Waiting for the select operation...");
int noOfKeys = selector.select();
System.out.println("The Number of selected keys are: " + noOfKeys);
Set selectedKeys = selector.selectedKeys();
Iterator itr = selectedKeys.iterator();
while (itr.hasNext()) {
SelectionKey ky = (SelectionKey) itr.next();
if (ky.isAcceptable()) {
// The new client connection is accepted
SocketChannel client = SS.accept();
client.configureBlocking(false);
// The new connection is added to a selector
client.register(selector, SelectionKey.OP_READ);
System.out.println("The new connection is accepted from the client: " + client);
} else if (ky.isReadable()) {
// Data is read from the client
SocketChannel client = (SocketChannel) ky.channel();
ByteBuffer buffer = ByteBuffer.allocate(256);
client.read(buffer);
String output = new String(buffer.array()).trim();
System.out.println("Message read from client: " + output);
if (output.equals("Bye Bye")) {
client.close();
System.out.println("The Client messages are complete; close the session.");
}
}
itr.remove();
} // end of while loop
} // end of for loop
}
}
客户端程序:
执行上面示例程序,得到以下结果 -
主程序的输出是:
Selector is open for making connection: true
Waiting for the select operation...
The Number of selected keys are: 1
The new connection is accepted from the client: java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:53823]
Waiting for the select operation...
The Number of selected keys are: 1
Message read from client: Time goes fast.
Waiting for the select operation...
The Number of selected keys are: 1
Message read from client: What next?
Waiting for the select operation...
The Number of selected keys are: 1
Message read from client: Bye Bye
The Client messages are complete; close the session.
客户端程序的输出是:
The Client is sending messages to server...
Time goes fast.
What next?
Bye Bye