java.nio.channels.SelectionKey
java 的 nio 中,SelectionKey
用四个标识来表示可进行某一事件
(某个事件易已经发生)
下面通过源码理解它的实现技巧
先看下源码:
// 插入一个事件
public abstract SelectionKey interestOps(int ops);
// 查询事件
public abstract int readyOps();
// 可进行读
public static final int OP_READ = 1 << 0;
// 可进行写
public static final int OP_WRITE = 1 << 2;
// 已经连接完成,可以进行读写
public static final int OP_CONNECT = 1 << 3;
// 可以接受新的连接
public static final int OP_ACCEPT = 1 << 4;
public final boolean isReadable() {
return (readyOps() & OP_READ) != 0;
}
public final boolean isWritable() {
return (readyOps() & OP_WRITE) != 0;
}
public final boolean isConnectable() {
return (readyOps() & OP_CONNECT) != 0;
}
public final boolean isAcceptable() {
return (readyOps() & OP_ACCEPT) != 0;
}
从上面的代码中可以看到,代码中用(readyOps() & OP_READ) != 0
来表示可以进行某个事件操作(这里是读事件)。
那么这个是怎么实现的呢?思考为什么(readyOps() & OP_READ) != 0
就表示可以进行读事件了?
首先要知道 &
是 java 的二进制位运算,只有二进制每一位的值都是 1 时,结果才是 1。(java 还支持其它位操作,可自己 Google)
即(二进制):
- 1 & 1 = 1
- 0 & 1 = 0
- 1 & 0 = 0
- 0 & 0 = 0
下面的这个表格里面有每个标识的二进制和十进制
readyOps | 十进制 | 二进制 |
---|---|---|
OP_READ | 1 | 00000001 |
OP_WRITE | 4 | 00000100 |
OP_CONNECT | 8 | 00001000 |
OP_ACCEPT | 16 | 00010000 |
从表格中可看到:
OP_READ 的1在第一位
OP_WRITE 的1在第三位
OP_CONNECT 的1在第四位
OP_ACCEPT 的1在第五位
OP_READ & OP_WRITE
二进制的&结果(二进制00000000
,十进制是零)
计算过程:
- OP_READ & OP_WRITE
- 00000001 # OP_READ
- 00000100 # OP_WRITE
- 00000000 # 结果
我们可以把这个四种值进行组合,他们&
的结果都是零(二进制00000000
),因为它们二进制形式的 1 都是在不同的位置上
因此只有readyOps()
是本身,结果才不是零
。即 OP_READ & OP_READ
= 00000001 & 00000001
结果是不是零
(二进制00000001
)
因此 (readyOps() & OP_READ) != 0
表示可以进行读事件
如果 readyOps()
的二进制是00000101
的时候,代表的什么事件?
00000101
& OP_READ =00000101
&00000001
=00000001
00000101
& OP_WRITE =00000101
&00000100
=00000100
上面的运算结果都不是零,代表了读事件(OP_READ
)&写(OP_WRITE
)事件!
那么00000101
是怎么来的,可通过 OP_READ | OP_WRITE
= 00000001
| 00000100
= 00000101
我们可以通过interestOps(int ops)
这个方法同时插入读事件&写事件
即: interestOps(OP_READ | OP_WRITE)