Java NIO選擇器
在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