IO 与 NIO

news2024/12/21 1:27:15

优质博文:IT-BLOG-CN

一、阻塞IO / 非阻塞NIO

阻塞IO:当一条线程执行read()或者write()方法时,这条线程会一直阻塞直到读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。

非阻塞NIONIO与原有的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的操作。NIO将以更加高效的方式进行文件读写操作。JAVA NIO的核心在于:通道Channel和缓冲区Buffer。通道表示打开IO设备(例如:文件、套接字)的连接。若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。对数据进行处理。

二、传统IO测试代码如下

当出现accept()read()等方法是就会阻塞。

/**
 * 传统socket服务端
 * @author -zhengzx-
 */
public class OioServer {

    @SuppressWarnings("resource")
    public static void main(String[] args) throws Exception {

        //创建socket服务,监听10101端口
        ServerSocket server=new ServerSocket(10101);
        System.out.println("服务器启动!");
        while(true){
            //获取一个套接字(阻塞)
            final Socket socket = server.accept();//(测试时可以通过:telnet 127.0.0.1 10101。进行测试)
            System.out.println("来个一个新客户端!");
            //业务处理
            handler(socket);
        }
    }

    /**
     * 读取数据
     * @param socket
     * @throws Exception
     */
    public static void handler(Socket socket){
            try {
                byte[] bytes = new byte[1024];
                InputStream inputStream = socket.getInputStream();

                while(true){
                    //读取数据(阻塞)
                    int read = inputStream.read(bytes);
                    if(read != -1){
                        System.out.println(new String(bytes, 0, read));
                    }else{
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                try {
                    System.out.println("socket关闭");
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    }
}

三、阻塞 IO解决办法

可以通过线程池创建多线程,为每一次连接创建一个新的线程来执行。问题是对于长连接而言,线程过多时会严重消耗系统资源导致性能下降。比较适合短连接的应用。

public static void main(String[] args) throws Exception {
    //创建线程池(可以通过线程解决阻塞问题、问题:每次连接都会创建一个线程,特别是长连接时特别消耗系统资源)
    ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    //创建socket服务,监听10101端口
    ServerSocket server=new ServerSocket(10101);
    System.out.println("服务器启动!");
    while(true){
        //获取一个套接字(阻塞)
        final Socket socket = server.accept();//(测试时可以通过:telnet 127.0.0.1 10101。进行测试)
        System.out.println("来个一个新客户端!");
        newCachedThreadPool.execute(new Runnable() {

            @Override
            public void run() {
                //业务处理
                handler(socket);
            }
        });
    }
}

四、NIO 的非阻塞模式

Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别,允许一条线程从Channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据。

*SelectorsJava NIOselectors允许一条线程去监控多个channels的输入,你可以向一个selector上注册多个channel,然后调用selectorselect()方法判断是否有新的连接进来或者已经在selector上注册时channel是否有数据进入。selector的机制让一个线程管理多个channel变得简单。

五、NIO示例代码如下

客户端使用SocketChannel,服务端使用ServerSocketChannel获取通道

public class NIOServerSocket {
    //定义一个socket入口
    private ServerSocketChannel serverSocket;
    //定义一个监听器
    Selector selector;
    public static void main(String[] args) throws IOException {
        NIOServerSocket nio =new NIOServerSocket();
        nio.initServer(8000);
        nio.listen();
    }
    public void initServer(int port) throws IOException {
        //获取一个serverSocket通道
        serverSocket = ServerSocketChannel.open();
        //设置为非阻塞状态(分为阻塞和非阻塞两种情况)
        serverSocket.configureBlocking(false);
        //将通道对应的serverSocketChannel绑定到端口上
        serverSocket.socket().bind(new InetSocketAddress(port));
        //获取一个通道管理器
        this.selector = Selector.open();
        //将通道管理器与通道进行绑定,并赋值SelectionKey.OP_ACCEPT事件
        //注册后,当事件到达后,select.select()会返回,如果没有返回,就一直阻塞。
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
    }
    public void listen() throws IOException {
        System.out.println("服务器启动");
        //轮询访问select.select()
        while(true) {
            //当事件到达时返回,否则一直阻塞
            Channel channel = selector.select();
            //获取selector中选中项的迭代器,相中的项为注册事件。
            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
            while(iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //删除已选的key,防止重复处理
                iterator.remove();
                handler(selectionKey);
            }
        }
    }
    public void handler(SelectionKey key) throws IOException {
        if(key.isAcceptable()) {
            handlerAccept(key);
        }else if(key.isReadable()) {
            handlerRead(key);
        }
    }
    public void handlerAccept(SelectionKey key) throws IOException {
        //获取以有的通道
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        //获取和客户端连接的通道
        SocketChannel accept = channel.accept();
        //设置为非阻塞
        accept.configureBlocking(false);
        // 在这里可以给客户端发送信息哦
        System.out.println("新的客户端连接");
        //连接成功之后,为了读取客户端传送的消息,需要设置读权限
        accept.register(selector, SelectionKey.OP_READ);
    }
    public void handlerRead(SelectionKey key) throws IOException {
        //服务器可读取消息,获取事件发生的Socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        //创建读取内容的缓存区buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int read = channel.read(buffer);
        if(read > 0) {
            byte[] array = buffer.array();
            String msg = new String(array).trim();
            System.out.println("服务端收到信息:" + msg);

            //会写
            ByteBuffer byteBuffer = ByteBuffer.wrap("success".getBytes());
            channel.write(byteBuffer);
        }else {
            System.out.println("客户端关闭");
            key.cancel();
        }
    }
}

六 、selector.select()

selector.select()虽阻塞,但可以通过selector.wakeup()唤醒selector执行,也可以通过selector.select(int timeout)设置时间限制,timeout时间后唤醒 selector

七、NIO提高性能

添加多线程,一个线程对应一个selector,端口的监听可以单独创建一个selector。(既Netty的工作原理)

总结: NIO允许你用一个单独的线程或几个线程管理很多个channels(网络的或者文件的),代价是程序的处理和处理IO相比更加复杂。如果你需要同时管理成千上万的连接,但是每个连接只发送少量数据,例如一个聊天服务器,用NIO实现会更好一些,相似的,如果你需要保持很多个到其他电脑的连接,例如P2P网络,用一个单独的线程来管理所有出口连接是比较合适的。

IO:如果你只有少量的连接但是每个连接都占有很高的带宽,同时发送很多数据,传统的IO会更适合

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Java 探索之路~大数据篇] 新时代大数据流处理入门指南

本文主要介绍大数据基础&#xff0c;以及 flink 流计算 文章目录 【基础知识】1. 批处理与流处理1.批处理2.流处理 2. 为什么需要一个优秀的流处理框架1. 股票交易的业务场景2.生产者——消费者模型3. 流处理框架要解决的诸多问题&#xff08;1&#xff09;可扩展性&#xff08…

JS 对象数组排序方法测试

输出 一.Array.prototype.sort() 1.默认排序 sort() sort() 方法就地对数组的元素进行排序&#xff0c;并返回对相同数组的引用。默认排序是将元素转换为字符串&#xff0c;然后按照它们的 UTF-16 码元值升序排序。 由于它取决于具体实现&#xff0c;因此无法保证排序的时…

将六西格玛设计融入汽车制造:实践之路

在快节奏的现代生活中&#xff0c;汽车早已不再仅仅是一种交通工具&#xff0c;而是成为了展现个性、追求品质生活的重要象征。为了满足消费者日益增长的品质需求&#xff0c;汽车制造商们纷纷将目光投向了六西格玛设计这一先进的质量管理方法。那么&#xff0c;如何将六西格玛…

现在如何才能开通微信公众号留言功能?

为什么公众号没有留言功能&#xff1f;2018年2月12日之后直到现在&#xff0c;新注册公众号的运营者会发现一个问题&#xff1a;无论是个人还是企业的公众号&#xff0c;在后台都找不到留言功能了。这对公众号来说绝对是一个极差的体验&#xff0c;少了一个这么重要的功能&…

AWS的S3存储桶设置生命周期规则

业务场景&#xff1a;周期性备份数据到s3存储桶&#xff0c;设置定期删除&#xff0c;只保留一定周期内的存储数据&#xff0c;节省存储空间减少花费 1. 点击存储桶选择管理--->创建生命周期规则 2. 设置名称等参数 点击创建即可

VUE实现Office文档在线编辑,支持doc/docx、xls/xlsx、ppt/pptx、pdf等

1.微软提供的在线Office预览&#xff08;只能预览&#xff0c;不能编辑&#xff09; https://view.officeapps.live.com/op/view.aspx?src服务器上文档地址&#xff08;http开头&#xff09; 2.国内在线Office方案&#xff1a; 腾讯文档、石墨文档、飞书 优势&#xff1a;跨…

光路科技:工业以太网交换机引领工业互联网新篇章

随着全球范围内工业4.0的浪潮不断涌动&#xff0c;工业互联网作为其核心驱动力&#xff0c;正引领着工业生产向智能化、网络化的崭新阶段迈进。在这一转型的浪潮中&#xff0c;光路科技凭借其卓越的工业互联设备与创新解决方案&#xff0c;正为工业互联网领域的发展注入新的活力…

Unity 常用的4种灯光、制作镜子、灯光的调用修改数值、

创建灯光时&#xff0c;一般用4种&#xff1a;定向光、点光源、聚光、区域光、 定向光&#xff1a;太阳 点光源&#xff1a;灯泡 聚光灯&#xff1a;手电筒 区域光&#xff1a;烘焙-贴图 灯光选择已烘焙 需要先选择被烘焙的物体&#xff0c;然后再选择Contribute GI 等待进…

网络工程师笔记7

路由器需要知道下一跳和出接口才能把数据转发出去 各个协议的优先级 直连&#xff1a;0 OSPF&#xff1a;10 ISIS&#xff1a;15 静态&#xff1a;60 RIP :100 静态路由 ip route-static <目的ip地址> 掩码 下一跳地址 例…

一文彻底搞懂Redis持久化

文章目录 1. Redis持久化方式2. RDB(快照)2.1 手动方式2.2 自动方式2.3 何时触发 RDB 持久化2.4 RDB 相关配置 3. AOF(追加日志文件)3.1 AOF 文件解读3.2 AOF 的写入与同步3.3 AOF 重写3.4 AOF 重写面临的问题3.5 AOF相关配置 4. 混合持久化 1. Redis持久化方式 Redis持久化是…

你知道什么是 BitMap 吗?

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

哪个超声波清洗机品牌值得入手?销量榜品牌值得选购!

在科技日益发展的今天&#xff0c;超声波清洗技术以其高效、便捷和深度清洁的特点&#xff0c;已经深入到生活的诸多领域&#xff0c;从精密仪器到珠宝首饰&#xff0c;从眼镜框到假牙&#xff0c;甚至是厨房用品的日常护理&#xff0c;都能见到超声波清洗机的身影。面对市场上…

第105讲:Mycat垂直分表实战:从规划到解决问题的完整指南

文章目录 1.垂直分表的背景2.垂直分表案例实战2.1.垂直分表规划2.2.配置Mycat实现垂直分表2.3.重启Mycat2.4.在Mycat命令行中导入数据结构2.5.查看由Mycat分表后每个分片上存储的表2.6.Mycat垂直分表后可能遇到的问题2.7.垂直分表完成 1.垂直分表的背景 我们的商城系统数据库&…

基于JavaWEB SpringBoot婚纱影楼摄影预约网站设计和实现

基于JavaWEB SSM SpringBoot婚纱影楼摄影预约网站设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言…

两天学会微服务网关Gateway-Gateway工作原理

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…

Vulnhub靶机:Bellatrix

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.4&#xff09; 靶机&#xff1a;Bellatrix&#xff08;10.0.2.9&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/hogwa…

【LangChain学习之旅】—(11) 记忆:通过Memory记住用户上次的对话细节

【LangChain学习之旅】—&#xff08;11&#xff09; 记忆&#xff1a;通过Memory记住客户上次买花时的对话细节 使用 ConversationChain使用 ConversationBufferMemory使用 ConversationBufferWindowMemory使用 ConversationSummaryMemory使用 ConversationSummaryBufferMemor…

VsCode搭建Spring Boot项目环境

VsCode搭建Spring Boot项目环境 1、前提条件&#xff1a;配置Java环境 下载安装JDK配置环境变量 2、VsCode配置SpringBoot环境 安装扩展 配置Maven 找到Maven配置文件&#xff0c;进行打开settings.json&#xff0c;添加如下代码&#xff1a; "workbench.iconThem…

码界深潜:全面解读软件工程的艺术与科学

&#x1f3e1; 基石构筑篇——软件工程基础理论及技能 &#x1f522; 编程语言选型与精修 于软件工程之浩瀚宇宙中&#xff0c;编程语言犹如各色画笔&#xff0c;每种语言的特性对应不同的创作领域。譬如Java倚仗跨平台兼容性和强大的面向对象机制&#xff0c;在企业级应用程序…

《GitHub新手入门指南:从零开始掌握基本用法》

在现代软件开发和技术社区中,GitHub已经成为了一个不可或缺的平台。它不仅是一个代码托管平台,更是一个技术交流、学习分享的社交平台。但对于初学者来说,GitHub可能会有些令人望而却步。本文将详细介绍GitHub的基本用法,帮助新手快速入门并融入这个充满活力的技术社区。 …