Java NIO Selector , SelectionKey , SocketChannel , ServerSocketChannel

本文介绍了Java NIO的非阻塞特性及其实现原理,重点讲解了Selector、SelectionKey、SocketChannel和ServerSocketChannel的使用。通过Selector监控多个Channel的事件,实现单线程管理多个网络连接,提升程序效率。文章还提供了具体的注册、选择就绪通道和取消注册等操作的详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一    NIO介绍

1. NIO是非阻塞的

    NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,假如没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。

2. 实现原理

    Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,假如有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等。

    Selector就是观察者,观察 Server 端的ServerSocketChannel  和 Client 端的 SocketChannel ;前提是它们需要先注册到 同一个Selector,即观察者中;

----详细说明

    NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。Selector内部原理实际是在做一个对所注册的Channel(SocketChannel)的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,它就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

while(!stop) {
            try {
                selector.select(1000);  // 等待客户端发请求  1000ms
                selector.selectedKeys().stream().forEach( key -> handleSelectionKey(key) );
            }catch(Exception e) {
                e.printStackTrace();
            }
        }

 

3. 小结

 

    从外界看,实现了流畅的I/O读写,不堵塞了。Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。

 

下文部分转载自  https://blog.youkuaiyun.com/robinjwong/article/details/41792623

二    Selector , SelectionKey  , SocketChannel , ServerSocketChannel 具体应用和功能

     NIO的通讯过程

1.    Selector  (选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接

    仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。

 

  1. java.nio.channels

  2. public abstract class Selector extends Object implements Closeable

 

1.1    Selector 的创建

通过调用Selector.open()方法创建一个Selector;Selector selector = Selector.open();

    isOpen() —— 判断Selector是否处于打开状态。Selector对象创建后就处于打开状态了。

    close() —— 当调用了Selector对象的close()方法,就进入关闭状态.。用完Selector后调用其close()方法会关闭该Selector,且使注册到该Selector上的所有SelectionKey实例无效。通道本身并不会关闭

 

1.2    ServerChanel  向 Selector 中注册

为了将Channel和Selector配合使用,必须将channel注册到selector上。

通过SelectableChannel。register()方法来实现。

 
  1. channel.configureBlocking(false);

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

    与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着FIleChannel与Selector不能一起使用。

    注意register()方法的第二个参数,这是一个”interest集合“,意思是在通过Selector监听Channel时对什么事件感兴趣。

可以监听四种不同类型的事件:

  • Connect
  • Accept
  • Read
  • Write

    通道触发了一个事件意思是该事件已经就绪。所以,某个channel成功连接到另一个服务器称为”连接就绪“。一个server socket channel准备号接收新进入的连接称为”接收就绪“。一个有数据可读的通道可以说是”读就绪“。等代写数据的通道可以说是”写就绪

### 回答1: JavaScript 中有五种基本数据类型: 1. 字符串 (string) 2. 数字 (number) 3. 布尔值 (boolean) 4. undefined 5. null 此外,JavaScript 还有一种复杂数据类型:对象 (object)。 ### 回答2: 在JavaScript中,有六种基本数据类型。 1. 数字(Number):用于表示数值。包括整数和浮点数,例如1、3.14等。 2. 字符串(String):用于表示文本数据。用引号(单引号或双引号)括起来,例如'hello'、"world"。 3. 布尔值(Boolean):用于表示真(true)或假(false)的逻辑值。 4. 空值(Null):用于表示一个空值或不存在的值。 5. 未定义(Undefined):用于表示未定义的值,即已声明但未赋值的变量。 6. 符号(Symbol):是ECMAScript 6中新增的一种数据类型,用于表示独一无二的值。 除了这六种基本数据类型,JavaScript还有一种复杂数据类型,叫做对象(Object)。对象是一种无序的数据集合,由多个键值对组成,键是字符串类型的属性名,值可以是任意类型的数据。 总结起来,JavaScript的基本数据类型有:数字、字符串、布尔值、空值、未定义和符号。而对象则是一种复杂数据类型。 ### 回答3: 在JavaScript中,有7种基本数据类型。 1. 数字(Number):用于表示数字,包括整数和浮点数,比如1、3.14等。 2. 字符串(String):用于表示文本,需要用单引号或双引号括起来,比如'hello'、"world"等。 3. 布尔值(Boolean):用于表示真(true)或假(false),用于条件判断和逻辑运算。 4. 空(Null):表示一个空值,常用于初始化一个变量。 5. 未定义(Undefined):表示一个未定义的值,常用于表示声明但未赋值的变量。 6. 对象(Object):用于表示复杂的数据结构,可以包含多个属性和方法。 7. 符号(Symbol):引入ES6中的新的数据类型,表示独一无二的值,用于创建对象的私有属性。 这些基本数据类型可以用来存储不同类型的数据,可以进行各种操作和运算。在JavaScript中,变量的类型是动态的,可以根据具体的值来自动推断出类型。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值