SelectionKey

65 阅读2分钟

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来表示可以进行某个事件的操作(这里为读事件)。

位运算

& 是java的二进制位运算,只有二进制每一位的值都是1时,结果才是1。

即(二进制):

  • 1 & 1 = 1
  • 0 & 1 = 0
  • 1 & 0 = 0
  • 0 & 0 = 0

解读

下面这个表格里面有每个标识的二进制和十进制

readyOps十进制二进制
OP_READ100000001
OP_WRITE400000100
OP_CONNECT800001000
OP_ACCEPT1600010000

OP_READ & OP_WRITE 的二进制的&结果

计算过程:

  • OP_READ & OP_WRITE

    • 00000001 # OP_READ
    • 00000100 # OP_WRITE
    • 00000000 # 结果

将四种值进行组合,他们&的结果都是零(二进制00000000),因为它们二进制形式的1都是在不同的位置上。

所以只有readOps()是本身,结果才不为零,因此(readOps() & OP_READ) != 0 表示可以进行读事件。

更进一步

如果readOps()的二进制是00000101的时候,代表的是什么事件?

  • 00000101 & OP_READ = 00000101 & 00000001 = 00000001
  • 00000101 & OP_WRITE = 00000101 & 00000100 = 00000100

上面运算结果都不为零,代表了读事件&写事件。

那么00000101是怎么来的,可以通过 OP_WRITE | OP_READ = 00000100 | 00000001 = 00000101

可以通过interesOps(int ops)这个方法同时插入读事件&写事件

即:interesOps(OP_WRITE | OP_READ)

参考文章