专栏首页码农知识点Java NIO与Java BIO的区别

Java NIO与Java BIO的区别

1.什么是Java NIO? 同步非阻塞io模式,拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。 Java NIO有三大组成部分:Buffer,Channel,Selector,通过事件驱动模式实现了什么时候有数据可读的问题。 Channel:相当于IO操作的载体,相当于一个硬件设备,一个文件,一个socket或是区别程序中的不同IO操作,如read,write。 channel类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。 通道可以异步地读写。 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

Buffer:用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。 channel 和 buffer 之间的交互如下:

CHANNEL BUFFER.png

Selector:Selector(选择器)是Java NIO中能够检测一到多个NIO通道,通道将关心的事件注册到selector 上,selector能够知晓通道是否为这些事件诸如读写事件做好数据准备。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。

selector工作模式.png

2.什么是Java BIO? 同步阻塞IO模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。不知道io操作中什么时候有数据可读,所以一直是阻塞的模式。 3.区别及应用 主要区别如下:

nio与bio区别.png

两种模式的差异对比:

首先,线程是较为重量级的资源。bio当并发量大,而后端服务或客户端处理数据慢时就会产生产生大量线程处于等待中,即上述的阻塞,是非常严重的资源浪费。此外,线程的切换也会导致cpu资源的浪费,单机内存限制也无法过多的线程,只能单向以流的形式读取数据。

bio工作模式.png

nio使用单线程或者只使用少量的多线程,多个连接共用一个线程,消耗的线程资源会大幅减小。并且当处于等待(没有事件)的时候线程资源可以释放出来处理别的请求,通过事件驱动模型当有accept/read/write等事件发生后通知(唤醒)主线程分配资源来处理相关事件。以buffer缓冲区的形式处理数据,处理更为方便。

nio工作模式.png

nio server demo:

Selector selector = Selector.open();  
ServerSocketChannel ssc = ServerSocketChannel.open();  
ssc.configureBlocking(false);  
ssc.socket().bind(new InetSocketAddress(port));  
  
ssc.register(selector, SelectionKey.OP_ACCEPT);  
  
while (true) {  
  
    // select()阻塞,等待有事件发生唤醒  
    int selected = selector.select();  
  
    if (selected > 0) {  
        Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();  
        while (selectedKeys.hasNext()) {  
            SelectionKey key = selectedKeys.next();  
            if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {  
              SocketChannel client = ((ServerSocketChannel) key.channel()).accept();
                // 处理 accept 事件  
                //注册read事件
                client.configureBlocking(false);
                client.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize));

            } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {  
                // 处理 read 事件  
               //注册write事件
            } else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {  
                // 处理 write 事件  
            }  
            selectedKeys.remove();  
        }  
    }  
} 

bio server demo

 ServerSocket serverSocket;
        try {
            serverSocket = new ServerSocket(8000);
            while (true){
                Socket socket = serverSocket.accept();
                new Thread(()->{
                    try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream =  socket.getOutputStream()) {

                        byte[] bytes =new byte[1024];
                        while (inputStream.read(bytes) != -1){
                            outputStream.write(bytes);
                            bytes = new byte[1024];
                        }

                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }).start();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

参考资料: http://ifeve.com/java-nio-vs-io/ http://zhhphappy.iteye.com/blog/2032893 http://wiki.jikexueyuan.com/project/java-socket/tcpserver.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JUC学习笔记(四)—线程池

    线程池 【死磕Java并发】—–J.U.C之线程池:ThreadPoolExecutor

    Monica2333
  • Java线程中断

    首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.res...

    Monica2333
  • JUC学习笔记(一)—锁工具类

    LockSupport类:用于阻塞线程,基于线程的阻塞。而wait,notify是基于对象的,用于synchronized同步块中。 使用和原理: 浅谈Ja...

    Monica2333
  • Tungsten Fabric入门宝典丨关于多集群和多数据中心

    由于在内部使用MPLS-VPN,因此Tungsten Fabric中的virtual-network可以扩展到其它Tungsten Fabric集群。

    Tungsten Fabric
  • JAVA反射--获取成员变量

    用户2965768
  • 人工智能如何通过眼球运动测量语言能力

    麻省理工学院研究人员的一项研究发现了一种判断人们学习英语水平的新方法:跟踪他们的眼球运动。

    思谱云汇
  • CreatorPrimer| CustomMaterial.js源码分析

    《ShaderHelper组件速递》一篇我们介绍了ShaderHelper组件的使用,以及如何定义一个shader程序并添加到ShaderHelper组件的pr...

    张晓衡
  • 你需要 GraphQL 吗?

    第一次了解到 GraphQL 是查阅 Github 文档时,偶然看到 v4 版本文档只要一个链接就可以完成所有获取数据和更新数据请求,当时看到觉得特别惊艳,能跳...

    Omniqia
  • CDH5升级到CDP7.1

    将Cloudera Enterprise CDH升级到更高版本的CDH和CDP数据中心版。

    大数据杂货铺
  • VHDL和verilog应该先学哪个?

      网上有太多的VHDL和verilog比较的文章,基本上说的都是VHDL和verilog之间可以实现同一级别的描述,包括仿真级、寄存器传输级、电路级,所以可以...

    窗户

扫码关注云+社区

领取腾讯云代金券