NIO死循环

原创 2015年11月17日 18:03:46

关于JAVA NIO死循环的研究

NIO写事件比较特殊,触发的条件取决于写缓冲区是否有空闲,不然会进入死循环。

直接上代码

服务端:

    public static void main(String[] args) {
        try {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.bind(new InetSocketAddress("127.0.0.1", 9999));
            serverChannel.configureBlocking(false);
            Selector sel = Selector.open();
            serverChannel.register(sel, SelectionKey.OP_ACCEPT);
            while(true){
                sel.select();
                Set<SelectionKey> set = sel.selectedKeys();
                System.out.println(set.size());
                Iterator<SelectionKey> iterator = set.iterator();
                while(iterator.hasNext()){
                    SelectionKey key = (SelectionKey)iterator.next();
                    iterator.remove();
                    handler(key);
                }
            }   
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void handler(SelectionKey key){

        SocketChannel client;
        Selector sel = key.selector();
        try {

            if(key.isAcceptable()){
                ServerSocketChannel ser = (ServerSocketChannel)key.channel();
                client = ser.accept();
                client.configureBlocking(false);
                client.register(sel,SelectionKey.OP_READ);
            }else if(key.isReadable()){
                SocketChannel se = (SocketChannel)key.channel();
                ByteBuffer ch = ByteBuffer.allocate(1024);
                se.read(ch);
                System.out.println(new String(ch.array()));
                ByteBuffer by = ByteBuffer.wrap(new String("我是服务器").getBytes());
                se.write(by);
                se.register(sel, SelectionKey.OP_WRITE);
            }else if(key.isWritable()){
                SocketChannel ch = (SocketChannel)key.channel();
                ByteBuffer by = ByteBuffer.wrap(new String("我是服务器").getBytes());
                ch.write(by);
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }


    }
}

客户端:

    public static void main(String[] args) {
        SocketChannel client;
        try {
            client = SocketChannel.open();
            Selector sel = Selector.open();
            client.configureBlocking(false);
            client.register(sel,SelectionKey.OP_CONNECT);
            //并不正在建立连接,直到调用client.finishConnect();
            client.connect(new InetSocketAddress("127.0.0.1", 9999));
            while(true){
                sel.select();
                Iterator<SelectionKey> it = sel.selectedKeys().iterator();
                while(it.hasNext()){
                    SelectionKey key = (SelectionKey)it.next();
                    handler(key);
                    it.remove();
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    public static void handler(SelectionKey key){
        if(key.isConnectable()){
            SocketChannel client = (SocketChannel)key.channel();
            Selector sel = key.selector();
            //连接就绪
            if(client.isConnectionPending()){
                try {
                    //真正建立连接
                    client.finishConnect();
                    client.configureBlocking(false);//非阻塞
                    client.write(ByteBuffer.wrap(new String("我是客户端").getBytes()));
                    client.register(sel, SelectionKey.OP_READ);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
            //读就绪
        }else if(key.isReadable()){
            read(key);
        }
    }
    public static void read(SelectionKey key){
        SocketChannel cl = (SocketChannel)key.channel();
        ByteBuffer by = ByteBuffer.allocate(1024);
        try {
            cl.read(by);
            System.out.println(new String(by.array()));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

上诉代码会进入死循环,原因是写事件key.isWritable()

写事件相对读事件比较特殊,一般来说,你最好不要注册写事件。写事件的就绪条件为底层缓冲区有空闲空间,而写缓冲区绝大部分时间都是有空闲空间的,所以当你注册写事件后,写操作一直是就绪的,selector会一直搜索到该事件(写操作),从而一直占用整个CPU资源,进入死循环。所以,只有当你确实有数据要写时再注册写操作,并在写完以后马上取消注册。一般不建议注册写事件。

写博客事件不长,有什么不正确请及时@我,谢谢

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

网上关于NIO客户端断开连接出现死循环的bug修复

懒得打字,原错误代码示例及其效果如下 import java.io.IOException; import java.net.InetSocketAddress; import java.nio.B...

es,bx编程索引法死循环算法.rar

  • 2010年04月13日 13:14
  • 682B
  • 下载

电脑死循环

  • 2013年01月05日 16:21
  • 88B
  • 下载

linux内核线程死锁或死循环(soft lockup)之后如何让系统宕机重启

在开发内核模块或驱动时,如果处理失误,导致内核线程中出现死锁或者死循环,你会发现,除了重启之外,你没有任何可以做的。这时你的输入不起任何作用,终端(不是指远程的ssh工具)只会在那重复的输出类似“BU...

定位死循环或者高CPU使用率问题

  • 2013年06月07日 17:11
  • 13KB
  • 下载

解决hibernate监听器死循环问题

  • 2016年03月21日 09:56
  • 68KB
  • 下载

json+hibernate死循环问题的一点见解

Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage...
  • lkl713
  • lkl713
  • 2014年02月19日 14:01
  • 4265

求和死循环

  • 2013年11月12日 15:35
  • 168B
  • 下载

java内部重定向死循环检例子

  • 2010年02月21日 12:45
  • 10KB
  • 下载

okHttp的简单运用以及cookie操作,302重定向死循环

为了完成学期实训,需要对新浪新闻网站进行读取,所以学习并封装了okhttp简单get和post的工具类。 本文参考了以下两篇文章: http://www.jcodecraeer.com/a/anz...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NIO死循环
举报原因:
原因补充:

(最多只允许输入30个字)