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资源,进入死循环。所以,只有当你确实有数据要写时再注册写操作,并在写完以后马上取消注册。一般不建议注册写事件。

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

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

java nio之数据读写时无限循环分析与解决

写这片文章是因为自己昨天刚解决了一个十个月前碰到的问题!当时苦于网上高手无人回答,也苦于自己当时没有时间去钻研为什么 ! 问题是:通过网上实例以及java网络编程这本书写java n...
  • haier_jiang
  • haier_jiang
  • 2010年08月17日 10:07
  • 4073

java之NIO select基本设计思路梳理

总结: 多路复用概念:允许一个线程阻塞等待多个fd文件描述符的集合,只要任意一个有数据就返回。举个例子,大楼有许多门,保安晚上为了防止窃贼,最简单的方法就是一直巡视每个门看是否被打开了。但保...
  • vincentff7zg
  • vincentff7zg
  • 2017年03月03日 15:06
  • 925

Java笔试面试题整理第七波

1、super的作用、transient关键字用法、构造方法、java NIO、for和foreach比较     在Java中super指代父类对象(直接父类),也就是说,super相当于是一个直接...
  • shakespeare001
  • shakespeare001
  • 2016年05月13日 08:43
  • 10188

python基础学习04(死循环)

死循环  这里True,代表1是真,0是假 i = 0 while True:   i = i + 1   if i == 50:      print 'I have got to the roun...
  • yujin2010good
  • yujin2010good
  • 2016年04月29日 00:14
  • 5987

多线程调试--死锁,死循环都可用这个方法

_doMonitor线程中,重复加同一个锁,引起死锁。 [root@localhostroot]#  gdb  attach  131081 (gdb) infothreads   26Threa...
  • wangwenwen
  • wangwenwen
  • 2013年10月15日 22:19
  • 2080

Shell中让程序造死循环的几种方式

有时候需要造个死循环,或者让程序一直运行下去,这个时候就要用到while,归纳汇总了让Shell脚本一直运行下去的几种方式:...
  • Jerry_1126
  • Jerry_1126
  • 2016年08月02日 19:24
  • 5532

for语句引起一个死循环而引发的思考!!!

对于一个简单地for语句,学过C的朋友可能觉得很简单,但是,看完下面这个看似简单程序还能想明白的朋友(实则并不简单), 那才是真的不错,,好了,不废话了,大家看代码吧!!! #include #i...
  • msdnwolaile
  • msdnwolaile
  • 2016年01月26日 02:27
  • 1637

shell脚本编程之“最简单的死循环”

http://www.2cto.com/os/201301/183822.html shell脚本编程之“最简单的死循环”   在linux下编程的程序猿都知道shell脚本,就算你不怎...
  • wenwenxiong
  • wenwenxiong
  • 2015年07月14日 19:57
  • 839

一个For语句导致死循环的例子

在Java开发中常用到For循环,它对简化业务处理,提高效率,非常有帮助。但要防止程序算法中可能导致死循环的情况,而且有的死循环还不好察觉。比如下面这个例子,算法极容易认为是50,实际上其结果是无穷大...
  • Jerry_1126
  • Jerry_1126
  • 2014年02月26日 10:47
  • 3395

linux下gdb调试多线程死循环

http://www.cppblog.com/elva/archive/2010/08/02/121943.html  1、我们首先要知道是哪个线程出了问题:    A、查进程  ps -ef | ...
  • yuanzhenhai
  • yuanzhenhai
  • 2011年01月05日 09:57
  • 1935
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NIO死循环
举报原因:
原因补充:

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