Java NIO选择器

在Java NIO中,选择器(Selector)是可选择通道的多路复用器,可用作可以进入非阻塞模式的特殊类型的通道。它可以检查一个或多个NIO通道,并确定哪个通道准备好了可以进行通信,即读取或写入。

选择器的用途是什么?

选择器(Selector)用于使用单个线程处理多个通道。 因此,它需要较少的线程来处理这些通道。 线程之间的切换对于操作系统来说是昂贵的。 因此,使用它可以提高系统效率。

下面来看看使用选择器来处理3个通道的线程的示意图:

下面是聚集原理的简单说明:

创建选择器

可以通过调用Selector.open()方法创建一个选择器,如下代码所示:

Selector selector = Selector.open();

Java

打开服务器套接字通道

下面来看看打开服务器套接字通道的例子:

ServerSocketChannel serverSocket = ServerSocketChannel.open();  
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 8099);  
serverSocket.bind(hostAddress);

Java

使用选择器选择通道

在使用选择器注册一个或多个通道时,可以调用select()方法之一。 该方法返回一个准备好进行要执行事件的通道,即:连接,读取,写入或接受。

可用于选择通道的各种select()方法有:

  • int select():由select()方法返回的整数值通知有多少个通道准备好进行通信。
  • int select(long TS):方法与select()相同,除了阻塞最大TS(毫秒)时间的输出。
  • int selectNow():它不阻止输出并立即返回任何准备好的通道。

  • selectedKeys() - 当调用了任何一个select()方法后,它将返回一个值,表示一个或多个通道准备就绪,那么我们可以通过使用选择的键集合来访问就绪通道,通过调用选择器selectedkeys()方法如下:

Set<SelectionKey> selectedKeys = selector.selectedKeys();

Java

可以迭代所选的键集合来访问准备好的信道,如下所示:

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();  
}

Java

上述循环迭代所选择的键集合中的键,以确定使用所选通道执行的操作。

完整的选择循环示意图如下所示:

基本选择器示例

主程序:

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
    }
}

Java

客户端程序:



Java

执行上面示例程序,得到以下结果 -

主程序的输出是:

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.

Shell

客户端程序的输出是:

The Client is sending messages to server...
Time goes fast.
What next?
Bye Bye

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智慧浩海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值