java的IO之NIO

NIO是一种同步非阻塞的I/O模型,在Java 1.4中引入了NIO框架,对应java.nio包,提供了channel、selector、buffer等。
NIO中的N可以理解为Non-blocking不在单纯是New,它支持面向缓冲的,基于通道的I/O操作方法。NIO提供了与传统BIO模型中的SocketServerSocket相对应的SocketChannelServerSocketChannel,两种不同的套接字通道实现两种通道都支持阻塞和非阻塞式的两种模式,阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性不好;非阻塞模式刚好相反,对于低负载的、低并发的应用程序,可以使用同步阻塞I/O来提高开发效率和维护性;对于高负载的、高并发的应用,应该使用NIO的非阻塞模式来开发。

NIO

NIO(Non-blocking I/O)是Java中的一种非阻塞式IO模型,它基于缓冲区(Buffer)和通道(Channel)的概念,提供了更高效的IO操作和更好的并发处理能力。NIO模型使用单个线程处理多个IO操作,通过选择器(Selector)来管理多个通道,实现非阻塞的IO操作。

NIO的相关概念和使用方式:

  • 通道(Channel):通道是NIO模型中的基本组件,用于读取和写入数据。通道提供了高效的数据传输能力,并且可以通过非阻塞方式进行IO操作。常见的通道类有FileChannel、SocketChannel和ServerSocketChannel等。

  • 缓冲区(Buffer):缓冲区是NIO模型中用于存储数据的对象。数据从通道读取到缓冲区,或从缓冲区写入到通道。缓冲区提供了对数据的高效访问和操作。常见的缓冲区类有ByteBuffer、CharBuffer和ByteBuffer等。

  • 选择器(Selector):选择器是NIO模型中的关键组件,用于管理多个通道的IO操作。通过选择器,可以将一个线程管理多个通道,实现非阻塞的IO操作。选择器会不断地轮询注册在其上的通道,发现有IO事件发生时进行处理。

  • 使用方式:

    1. 创建通道:通过Channel类的工厂方法创建通道对象,如FileChannel.open()、SocketChannel.open()等。
    2. 创建缓冲区:通过Buffer类的静态方法创建缓冲区对象,如ByteBuffer.allocate()、CharBuffer.allocate()等。
    3. 注册通道:将通道注册到选择器上,通过SelectableChannel.register()方法实现。
    4. 选择就绪通道:通过选择器的select()方法选择就绪的通道,进行相应的IO操作。
    5. 处理IO事件:根据不同的IO事件类型,进行读取、写入或其他操作。
    6. 关闭通道:在完成IO操作后,及时关闭通道,释放资源。

BIO模式的操作

BIO 以流的方式处理数据,面向流的 BIO 一次处理一个字节数据:一个输入流产生一个字节数据,一个输出流消费一个字节数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责复杂处理机制的一部分。不利的一面是,面向流的 I/O 通常相当慢。
请添加图片描述

NIO模式的操作

NIO 以块的方式处理数据,面向块的 NIO 一次处理一个数据块,按块处理数据比按流处理数据要快得多。但是面向块的 NIO 缺少一些面向流的 BIO 所具有的优雅性和简单性。
请添加图片描述

解决的问题:

NIO可以用来解决传统的阻塞IO模型中的一些问题,包括:

  • 高并发处理能力:NIO模型使用单个线程处理多个IO操作,通过选择器(Selector)管理多个通道,实现非阻塞的IO操作。这样可以提高系统的并发处理能力,减少线程数量和资源消耗。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class HighConcurrencyServer {
    public static void main(String[] args) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);

            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                selector.select();

                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isAcceptable()) {
                        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                        SocketChannel clientChannel = serverChannel.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        clientChannel.read(buffer);
                        buffer.flip();
                        //TODO处理读取到的数据
                        // ...

                        clientChannel.close();
                    }

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

  • 资源利用率提升:由于NIO模型使用单个线程处理多个IO操作,可以更有效地利用系统资源,避免了为每个连接创建一个独立线程的资源浪费。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class ResourceUtilizationServer {
    public static void main(String[] args) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);

            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                selector.select();

                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isAcceptable()) {
                        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                        SocketChannel clientChannel = serverChannel.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        clientChannel.read(buffer);
                        buffer.flip();
                        //TODO处理读取到的数据
                        // ...

                        clientChannel.close();
                    }

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

  • 非阻塞IO操作:NIO模型中的IO操作是非阻塞的,即当没有数据可读取时,IO操作不会被阻塞,而是立即返回。这样可以避免线程被长时间阻塞,提高系统的响应性能。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class NonBlockingIOExample {
    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("example.com", 80));

            while (!socketChannel.finishConnect()) {
                //TODO等待连接完成
                //....
            }

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("Hello, Server".getBytes());
            buffer.flip();
            socketChannel.write(buffer);

            buffer.clear();
            socketChannel.read(buffer);
            buffer.flip();
            //TODO处理读取到的数据
            // ...

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

  • 选择器机制:NIO模型通过选择器(Selector)来管理多个通道的IO操作。选择器会不断地轮询注册在其上的通道,发现有IO事件发生时进行处理,避免了传统阻塞式IO模型中需要为每个通道创建一个线程的开销。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class SelectorExample {
    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();

            SocketChannel channel1 = SocketChannel.open();
            channel1.configureBlocking(false);
            channel1.connect(new InetSocketAddress("example.com", 80));
            channel1.register(selector, SelectionKey.OP_CONNECT);

            SocketChannel channel2 = SocketChannel.open();
            channel2.configureBlocking(false);
            channel2.connect(new InetSocketAddress("example.org", 80));
            channel2.register(selector, SelectionKey.OP_CONNECT);

            while (true) {
                selector.select();

                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isConnectable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        if (channel.isConnectionPending()) {
                            channel.finishConnect();
                        }
                        //TODO 处理连接完成事件
                        // ...
                    }

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

  • 灵活的缓冲区操作:NIO模型使用缓冲区(Buffer)来读取和写入数据,提供了灵活的数据操作方式。可以直接操作缓冲区来读取、写入数据,而无需通过输入流和输出流的方式。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class BufferExample {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("input.txt");
            FileOutputStream fos = new FileOutputStream("output.txt");

            FileChannel inputChannel = fis.getChannel();
            FileChannel outputChannel = fos.getChannel();

            ByteBuffer buffer = ByteBuffer.allocate(1024);

            while (inputChannel.read(buffer) != -1) {
                buffer.flip();
                outputChannel.write(buffer);
                buffer.clear();
            }

            inputChannel.close();
            outputChannel.close();

            fis.close();
            fos.close();

            System.out.println("文件复制成功.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NIO和BIO

区别

  • 阻塞 vs 非阻塞:BIO模型是阻塞式IO模型,即当没有数据可读取时,IO操作会被阻塞,直到有数据可读取。而NIO模型是非阻塞式IO模型,当没有数据可读取时,IO操作不会被阻塞,而是立即返回。

  • 线程模型:BIO模型使用一个线程处理一个连接,当有多个连接时,需要创建多个线程,可能导致资源浪费和性能下降。而NIO模型使用单个线程处理多个连接,通过选择器(Selector)管理多个通道,实现非阻塞的IO操作。

  • 缓冲区操作:BIO模型使用字节流或字符流进行数据读写,而NIO模型使用缓冲区(Buffer)进行数据读写,提供了更灵活的数据操作方式。

作用

  • BIO:BIO模型适用于连接数较少、并发要求不高的简单应用场景。它简单易用,可靠性高,适合于对数据完整性和可靠性要求较高的场景。

  • NIO:NIO模型适用于高并发、大规模的应用场景,可以提高系统的并发处理能力和资源利用率。它具有高性能、非阻塞的特性,适合于对并发性能要求较高的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/481530.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

论文阅读之LORA: LOW-RANK ADAPTATION OF LARGE LAN- GUAGE MODELS(2021)

文章目录 论文地址主要内容主要贡献模型图技术细节实验结果 论文地址 LORA: LOW-RANK ADAPTATION OF LARGE LAN- GUAGE MODELS 主要内容 这篇文章的主要内容是介绍了一种名为LoRA&#xff08;Low-Rank Adaptation&#xff09;的技术&#xff0c;这是一种针对大型语言模型进行…

阅读MySQL知识4

一、MySQL数据库主从同步延迟产生的原因 MySQL的主从复制都是单线程的操作&#xff0c;主库对所有DDL和DML产生的日志写进binlog&#xff0c;由于binlog是顺序写&#xff0c;所以效率很高。 Slave的SQL Thread线程将主库的DDL和DML操作事件在slave中重放。DML和DDL的IO操作…

【欧拉函数+快速幂】第十四届蓝桥杯省赛C++ C组 Java A组/研究生组 Python 研究生组《互质数的个数》(C++)

【题目描述】 给定 a,b&#xff0c;求 1≤x< 中有多少个 x 与 互质。 由于答案可能很大&#xff0c;你只需要输出答案对 998244353 取模的结果。 【输入格式】 输入一行包含两个整数分别表示 a,b&#xff0c;用一个空格分隔。 【输出格式】 输出一行包含一个整数表示…

8-深度学习

声明 本文章基于哔哩哔哩付费课程《小白也能听懂的人工智能原理》。仅供学习记录、分享&#xff0c;严禁他用&#xff01;&#xff01;如有侵权&#xff0c;请联系删除 目录 一、知识引入 &#xff08;一&#xff09;深度学习 &#xff08;二&#xff09;Tensorflo…

Java全栈课程之Linux———基本属性

一、看懂文件属性 Linux系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。为了保护系统的安全性&#xff0c;Linux系统对不同的用户访问同一文件&#xff08;包括目录文件&#xff09;的权限做了不同的规定。 在Linux中我们可以使…

深入理解Ubuntu22:探索Linux操作系统的功能与应用

一、linux &#xff08;一&#xff09;、安装 1、电脑可以安装双系统&#xff0c;即在一套硬件上只能同时运行一个操作系统&#xff0c;例&#xff1a;C盘安装win&#xff0c;D盘安装linux。 2、虚拟机 虚拟机需要硬件支持&#xff0c;并需开启VT-x. 如&#xff1a;Virtual…

Ubuntu18.04显示--有线连接未托管

引用: Ubuntu18.04连不网 报"有线连接未托管"_ubuntu20.04以太网未托管-CSDN博客 正文 虚拟机环境配置&#xff1a; VirtaualBox Ubuntu18.04桌面版 问题现象&#xff1a; Ubuntu18.04虚拟机的桌面上提示“有线连接未托管”&#xff0c;虚拟机不能上网&#xf…

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有哪些缺点?

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳也存在一些缺点&#xff0c;具体如下&#xff1a; 成本较高&#xff1a;相对于传统的塑料或金属材料&#xff0c;UV树脂胶液的成本较高&#xff0c;需要更多的材料和工艺成本。制作难度较大&#xff1a;由于UV树脂的特殊…

鸿蒙ArkTS实战开发-Native XComponent组件的使用

介绍 本篇Codelab主要介绍如何使用XComponent组件调用NAPI来创建EGL/GLES环境&#xff0c;实现在主页面绘制一个正方形&#xff0c;并可以改变正方形的颜色。本篇CodeLab使用Native C模板创建。 如图所示&#xff0c;点击绘制矩形按钮&#xff0c;XComponent组件绘制区域中渲…

校招岗位大解析

校园招聘岗位需要综合考虑岗位描述、行业背景、公司文化、职业发展路径、技能要求、薪酬福利以及公司口碑等多个方面的因素&#xff0c;全面了解并综合考虑这些因素&#xff0c;才能更好地选择适合自己的岗位&#xff0c;实现个人职业发展目标。 1. 软件/后端/前端开发 软件/…

【SpringBoot】如何定义接口

定义get接口 使用GetMapping定义一个基本get接口 RestController //表示定义一个json格式返回给前端 public class test {private Map<String,Object> map new HashMap<>();GetMapping(value "/test") //定义接口路径public Object userInfo(Strin…

搭建Linux内核开发环境——保姆教程(持续更新中)

搭建Linux内核开发环境——保姆教程&#xff08;持续更新中&#xff09; git版本管理汇编器链接器调试器编辑器构建系统模拟器文档工具图形设计工具 在此文中&#xff0c;持续完善&#xff0c;搭建内核开发环境的细节&#xff0c;有需要的小伙伴儿可以持续关注下 git版本管理 …

【小白入门篇1】GPT到底是怎样练成?

由于具有代表性的OpenAI公司GPT模型并没有开源&#xff0c;所以本章节是参考一些开源和现有课程&#xff08;李宏毅&#xff09;讲解ChatGPT原理。本章没有涉及到很多数学运算&#xff0c;比较适合小白了解GPT到底是怎么练成。GPT的三个英文字母分别代表Generative(生成式)&…

【LeetCode】升级打怪之路 Day 27:回溯算法 — 单词拆分问题

今日题目&#xff1a; 140. 单词拆分 II139. 单词拆分 参考文章&#xff1a;回溯算法&#xff1a;单词拆分 今天主要做了两道单词拆分的问题&#xff0c;都是需要使用回溯算法来解决&#xff0c;第一个题目难度不大&#xff0c;第二个题目需要在“剪枝”上多做一些功夫&#xf…

电脑共享文件使用记录怎么查

共享文件是指在网络环境下&#xff0c;多台计算机之间或同一台计算机的不同用户之间&#xff0c;能够对文件进行共享的一种机制。 通过共享文件&#xff0c;用户可以方便地在多台计算机之间传输和访问文件&#xff0c;实现文件资源的共享和协作。 在共享文件的设置中&#xf…

基于modbus TCP实现EPICS与西门子S7 1200系列1215C PLC的通信

PLC介绍 西门子系列PLC在国内的市场占比第一&#xff0c;1200系列中小型PLC&#xff0c;因其众多的产品序列、强大的通讯功能和丰富扩展模块&#xff0c;被使用在工业生产、自动化生产线、智能制造、机器人等各行各业。根据CPU的供电电源的型号和数字量输出的类型&#xff0c;…

FANUC机器人零点标定的基本步骤(出厂数据)

FANUC机器人零点标定的基本步骤(出厂数据) FANUC 零点数据存在问题的机器人通常会出现以下几种报警: (1)SRVO-062报警 - 脉冲编码器数据丢失,机器人完全不能动,具体消除方法可参考以下链接中的内容: FANUC机器人SRVO-062报警原因分析及处理对策 (2)SRVO-075报警 -…

某智慧化平台实施方案—资料原件word

1.概述 2.项目介绍 3.项目实施 4.实施计划 5.人员培训 6.项目验收 7.售后服务 8.项目保障措施 软件全套资料原件获取进主页。

软件测试 -- Selenium常用API全面解答(java)

写在前面 // 如果文章有问题的地方, 欢迎评论区或者私信指正 目录 什么是Selenium 一个简单的用例 元素定位 id定位 xpath定位 name定位 tag name 定位和class name 定位 操作元素 click send_keys submit text getAttribute 添加等待 显示等待 隐式等待 显示等…

【STC8A8K64D4开发板】第2-17讲:PCA实现数模转换(DAC)

第2-17讲&#xff1a;PCA实现数模转换&#xff08;DAC&#xff09; 学习目的了解DAC数模转换原理及RC积分电路原理。掌握STC8A8K64D4系列单片机实现DAC功能的硬件和软件设计。 DAC简介 DAC (全称是Digital to Analog Convertor)数模转换器是一种将数字信号转换为模拟信号&a…