并发编程之Java中Selector

系列文章目录



前言

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。
在这里插入图片描述


Selector提供选择执行已经就绪的任务的能力,使得多元 I/O 成为可能,就绪选择和多元执行使得单线程能够有效率地同时管理多个 I/O channel。

C/C++许多年前就已经有 select()和 poll()这两个POSIX(可移植性操作系统接口)系统调用可供使用。许多os也提供相似的功能,但对Java 程序员来说,就绪选择功能直到 JDK 1.4 才成为可行方案。
在这里插入图片描述
Selector的创建过程如下:

// 1.创建Selector
Selector selector = Selector.open();
 
// 2.将Channel注册到选择器中
// ....... new channel的过程 ....
 
//Notes:channel要注册到Selector上就必须是非阻塞的,所以FileChannel是不可以使用Selector的,因为FileChannel是阻塞的
channel.configureBlocking(false);
 
// 第二个参数指定了我们对 Channel 的什么类型的事件感兴趣
SelectionKey key = channel.register(selector , SelectionKey.OP_READ);
 
// 也可以使用或运算|来组合多个事件,例如
SelectionKey key = channel.register(selector , SelectionKey.OP_READ | SelectionKey.OP_WRITE);
 
// 不过值得注意的是,一个 Channel 仅仅可以被注册到一个 Selector 一次, 如果将 Channel 注册到 Selector 多次, 那么其实就是相当于更新 SelectionKey 的 interest set.

一个Channel在Selector注册其代表的是一个SelectionKey事件

SelectionKey的类型包括:
OP_READ:可读事件;值为:1<<0

OP_WRITE:可写事件;值为:1<<2

OP_CONNECT:客户端连接服务端的事件(tcp连接),一般为创建SocketChannel客户端channel;值为:1<<3

OP_ACCEPT:服务端接收客户端连接的事件,一般为创建ServerSocketChannel服务端channel;值为:1<<4

一个Selector内部维护了三组keys:

key set:
当前channel注册在Selector上所有的key;可调用keys()获取

selected-key set:当前channel就绪的事件;可调用selectedKeys()获取

cancelled-key:主动触发SelectionKey#cancel()方法会放在该集合,前提条件是该channel没有被取消注册;不可通过外部方法调用

Selector类中总共包含以下10个方法:
open():创建一个Selector对象

isOpen():是否是open状态,如果调用了close()方法则会返回false

provider():获取当前Selector的Provider

keys():如上文所述,获取当前channel注册在Selector上所有的key

selectedKeys():获取当前channel就绪的事件列表

selectNow():获取当前是否有事件就绪,该方法立即返回结果,不会阻塞;如果返回值>0,则代表存在一个或多个

select(long timeout):selectNow的阻塞超时方法,超时时间内,有事件就绪时才会返回;否则超过时间也会返回

select():selectNow的阻塞方法,直到有事件就绪时才会返回

wakeup():调用该方法会时,阻塞在select()处的线程会立马返回;(ps:下面一句划重点)即使当前不存在线程阻塞在select()处,那么下一个执行select()方法的线程也会立即返回结果,相当于执行了一次selectNow()方法

close(): 用完Selector后调用其close()方法会关闭该Selector,且使注册到该Selector上的所有SelectionKey实例无效。channel本身并不会关闭。

关于SelectionKey
谈到Selector就不得不提SelectionKey,两者是紧密关联,配合使用的;如上文所示,往Channel注册Selector会返回一个SelectionKey对象,

这个对象包含了如下内容:

interest set,当前Channel感兴趣的事件集,即在调用register方法设置的interes set

ready set

channel

selector

attached object,可选的附加对象

interest set

可以通过SelectionKey类中的方法来获取和设置interes set

// 返回当前感兴趣的事件列表
int interestSet = key.interestOps();
 
// 也可通过interestSet判断其中包含的事件
boolean isInterestedInAccept  = interestSet & SelectionKey.OP_ACCEPT;
boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInRead    = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite   = interestSet & SelectionKey.OP_WRITE;    
 
// 可以通过interestOps(int ops)方法修改事件列表
key.interestOps(interestSet | SelectionKey.OP_WRITE);

ready set

当前Channel就绪的事件列表

int readySet = key.readyOps();
 
// 也可通过四个方法来分别判断不同事件是否就绪
key.isReadable();    //读事件是否就绪
key.isWritable();    //写事件是否就绪
key.isConnectable(); //客户端连接事件是否就绪
key.isAcceptable();  //服务端连接事件是否就绪

channel和selector

我们可以通过SelectionKey来获取当前的channel和selector

// 返回当前事件关联的通道,可转换的选项包括:`ServerSocketChannel`和`SocketChannel`
Channel channel = key.channel();
 
//返回当前事件所关联的Selector对象
Selector selector = key.selector();

attached object

我们可以在selectionKey中附加一个对象:

key.attach(theObject);
Object attachedObj = key.attachment();

或者在注册时直接附加:

SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);
  • 29
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Java毕设王

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

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

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

打赏作者

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

抵扣说明:

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

余额充值