解决方案 »

  1.   

    关于OP_WRITE事件:
        只要socket空闲就会触发这个事件,网上了解到基本95%以上时间都会触发这个事件。
        所以网上都是推荐有数据写入时才临时注册这个事件,发送数据后再取消这个事件。
        引用火龙果的话:“有一些 NIO 框架就很少注册 OP_WRITE 事件的,直接写入,如果不适合时就会产生阻塞直到能写为止。
        OP_WRITE 比 OP_READ 等事件处理麻烦很多,一不小心就会对性能产生严重的影响。 ”
    关于OP_WRITE事件进一步了解
        不对OP_WRITE进行处理的样例:
            while (bb.hasRemaining()) {
                socketChannel.write(bb);
            }
        这样写在大多数的情况下都没有什么问题。但是在客户端的网络环境很糟糕的情况下,服务器会遭到很沉重的打击。
      因为如果客户端的网络或者是中间交换机的问题,使得网络传输的效率很低,这时候会出现服务器已经准备好的返回结果无法通过TCP/IP层传输到客户端。这时候在执行上面这段程序的时候就会出现以下情况:
      (1) bb.hasRemaining()一直为“true”,因为服务器的返回结果已经准备好了。
      (2) socketChannel.write(bb)的结果一直为0,因为由于网络原因数据一直传不过去。
      (3) 因为是异步非阻塞的方式,socketChannel.write(bb)不会被阻塞,立刻被返回。
      (4) 在一段时间内,这段代码会被无休止地快速执行着,消耗着大量的CPU的资源。事实上什么具体的任务也没有做,一直到网络允许当前的数据传送出去为止。
      

  2.   

    阻塞到写完我觉得不是一个好方法,就像你说的如果一直写不完那么其他事都不用做了。CPU一直在空转。应该是直到写完才取消掉写事件。
    private void writeable(SelectionKey key) throws IOException {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            BufferManager manager = (BufferManager) key.attachment();        int len = manager.outputWriteBuffer(socketChannel);
            if (len == EOF_FLAG) {
                throw new ConnectException("close channel.");
            }        if (manager.isCompleteWrite()) { // 代码1
                manager.rest();
                synchronized (ioSelectorsSyns.get(key.selector())) {
                    key.selector().wakeup();
                    key.interestOps(SelectionKey.OP_READ);
                }
            }
        }
    这里每次都会去检测缓冲是否已经写完,写完后立即取消掉这个管道的写事件,没有就继续等下次可写时再写。决不能阻塞掉NIO的选择器线程。