JAVA BIO,NIO,AIO区别(建议收藏)

news2024/9/23 7:28:09

Java中的IO原理

首先Java中的IO都是依赖操作系统内核进行的,我们程序中的IO读写其实调用的是操作系统内核中的read&write两大系统调用。

操作系统内核是如何进行IO交互的呢?

  • 网卡中的收到经过网线传来的网络数据,并将网络数据写到内存中。
  • 当网卡把数据写入到内存后,网卡向cpu发出一个中断信号,操作系统便能得知有新数据到来。
  • 通过网卡中断程序去处理数据。将内存中的网络数据写入到对应socket的接收缓冲区中。
  • 当接收缓冲区的数据写好之后,应用程序开始进行数据处理。
  • 处理完毕,释放相关资源(释放socket的缓存输入流)。

JAVA中的IO和OS中的IO很像,而BIO、NIO、AIO之间的区别就在于这些操作是同步还是异步,阻塞还是非阻塞。

同步与异步

案例代码

public class Test {

   //这里假设a方法业务复杂,执行需要耗费3秒的世时间
   public static void a(){
       try {
           Thread.sleep(3000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("testA");
   }

    public static void b(){
        System.out.println("testB");
    }

    public static void main(String[] args) {
        a();
        b();
    }	
}

同步指的是调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为,参考如上main方法中的执行情况,b方法必须等a方法执行完毕才能执行,所以此时a和b是同步执行的

public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            a();
        }
    });

    b();
}

异步指的是调用立刻返回,调用者不必等待方法内的代码执行结束,就可以继续后续的行为,通常是额外开始一个线程去执行a方法(方法执行完毕可能会涉及到回调),b方法则依然是main方法的主线在处理,这种情况下方法a不必等到方法b完成即可开始执行,所以a和b是异步执行的

开发经验
通常在业务需求中,当上下文内容没有关联的时候,上一个操作比较耗时(例如a方法), 我们无需等待上一个执行结束才开始下一个执行,本质就是为了解决主线程的阻塞,尽可能提高接口的响应速度

阻塞与非阻塞

阻塞与非阻塞的区别主要是单个线程内遇到同步等待时,是否在原地不做任何操作。

  • 阻塞指的是遇到同步等待后,一直在原地等待同步方法处理完成,即每一个请求都要对应一个专门的线程去处理,例如上面的代码server.accept();
  • 非阻塞指的是遇到同步等待,不在原地等待,先去做其他的操作,隔断时间再来观察同步方法是否完成,往往是一个线程跟踪多个 socket 状态,哪个socket就绪了线程就去操作哪个socket。

BIO通信模型图

概念

BIO本身是身是同步阻塞模式,线程发起IO请求后,一直阻塞IO,直到相关请求处理完毕后,网络通信模型都是一请求一应答的方式,虽然简化了上层的应用开发,但在性能和可靠性方面存在着巨大瓶颈,试想一下如果每个请求都需要新建一个线程来专门处理,那么在高并发的场景下,机器资源很快就会被耗尽

BIO架构模型

在这里插入图片描述

代码模拟

public class BIOServer {

    public static void main(String[] args) throws Exception {
        //线程池机制
        //思路
        //1. 创建一个线程池
        //2. 如果有客户端连接,就创建一个线程,与之通讯(单独写一个方法)
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        //创建ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
        System.out.println("服务器启动了");
        while (true) {
            System.out.println("线程信息id = " + Thread.currentThread().getId() + "名字 = " + Thread.currentThread().getName());
            //监听,等待客户端连接
            System.out.println("等待连接....");
            //会阻塞在accept()
            final Socket socket = serverSocket.accept();
            System.out.println("连接到一个客户端");
            //就创建一个线程,与之通讯(单独写一个方法)
            newCachedThreadPool.execute(new Runnable() {
                public void run() {//我们重写
                    //可以和客户端通讯
                    handler(socket);
                }
            });
        }
    }

    //编写一个handler方法,和客户端通讯
    public static void handler(Socket socket) {
        try {
            System.out.println("线程信息id = " + Thread.currentThread().getId() + "名字 = " + Thread.currentThread().getName());
            byte[] bytes = new byte[1024];
            //通过socket获取输入流
            InputStream inputStream = socket.getInputStream();
            //循环的读取客户端发送的数据
            while (true) {
                System.out.println("线程信息id = " + Thread.currentThread().getId() + "名字 = " + Thread.currentThread().getName());
                System.out.println("read....");
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println(new String(bytes, 0, read));//输出客户端发送的数据
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭和client的连接");
            try {
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

打开cmd用来模拟一个本地客户端进程,相关命令如下

telnet 127.0.0.1 6666 <!-- 和BIOServer建立通信连接 ->

send 'ok' <!-- 向客户端发送消息 ->

服务器端代码中日志打印

服务器启动了
线程信息id = 1名字 = main
等待连接....
连接到一个客户端
线程信息id = 1名字 = main
等待连接....
线程信息id = 12名字 = pool-1-thread-1
线程信息id = 12名字 = pool-1-thread-1

线程信息id = 12名字 = pool-1-thread-1
read....
线程信息id = 12名字 = pool-1-thread-1
read....
线程信息id = 12名字 = pool-1-thread-1
read....
'ok'   <!-- 我们客户端测试的那条消息 ->
线程信息id = 12名字 = pool-1-thread-1
read....
线程信息id = 12名字 = pool-1-thread-1
read....
线程信息id = 12名字 = pool-1-thread-1
read....

同理,打开多个cmd模拟多个客户端进程和服务器端建立并保持连接,你们会发现每个客户端进程都会服务器端都会从线程池中取出不同的线程单独处理处理这个连接,负责这个连接的读read写write操作的完成

经过测试,我们可以很容易看到BIO和弊端

  • 客户端请求和线程之间是总是一对一的关系,那意味着客户端连接即便是没有任何读写操作,这个线程的工作就很闲,造成线程资源的浪费
  • 如果是高并发情况,需要使用大量线程去完成处理,浪费大量线程资源,这种架构设计是不适用于处理高并发情况的

NIO

同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理,当前连接没有请求,那么线程则切换到其它有读写操作的连接去处理,线程和客户端连接请求间不需要一一再对应,一个线程可以同时处理多个客户的连接的请求,NIO 是面向缓冲区,或者面向块编

NIO架构模型

在这里插入图片描述
NIO 全称 Java non-blocking IO即非阻塞型IO

NIO 有三大核心部分

  • 缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块
  • Channel 提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由 Buffer
  • Selector(选择器):用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道
    在这里插入图片描述

Channel和Buffer的关系

Channel和Buffer是一一对应的,如果说BIO基于字节流和字符流进行操作,那么NIO则是基于Channel和Buffer缓冲块进线操作的,Channel和Buffer是双向的,数据总是由Buffer写入Channel,或者从Channel中读取到Buffer

图解NIO三大核心组件

在这里插入图片描述

NIO案例代码

在这里插入图片描述

public class NIOFileChannel03 {

    public static void main(String[] args) throws Exception {

        FileInputStream fileInputStream = new FileInputStream("1.txt");
        FileChannel fileChannel01 = fileInputStream.getChannel();
        FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
        FileChannel fileChannel02 = fileOutputStream.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        
        while (true) { //循环读取

            //这里有一个重要的操作,一定不要忘了
            /*
            public final Buffer clear() {
                position = 0;
                limit = capacity;
                mark = -1;
                return this;
            }
            */
            byteBuffer.clear(); //清空 buffer
            int read = fileChannel01.read(byteBuffer);
            System.out.println("read = " + read);
            if (read == -1) { //表示读完
                break;
            }

            //将 buffer 中的数据写入到 fileChannel02--2.txt
            byteBuffer.flip();
            fileChannel02.write(byteBuffer);
        }

        //关闭相关的流
        fileInputStream.close();
        fileOutputStream.close();
    }
}

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

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

相关文章

Flink01: 基本介绍

一、什么是Flink 1. Flink是一个开源的分布式&#xff0c;高性能&#xff0c;高可用&#xff0c;准确的流处理框架 &#xff08;1&#xff09;分布式&#xff1a;表示flink程序可以运行在很多台机器上&#xff0c; &#xff08;2&#xff09;高性能&#xff1a;表示Flink处理性…

LabVIEW使用实时跟踪查看器调试多核应用程序

LabVIEW使用实时跟踪查看器调试多核应用程序随着多核CPU的推出&#xff0c;开发人员现在可以在LabVIEW的帮助下充分利用这项新技术的功能。并行编程在为多核CPU开发应用程序时提出了新的挑战&#xff0c;例如同步多个线程对共享内存的并发访问以及处理器关联。LabVIEW可自动处理…

基于SpringBoot+vue的无偿献血后台管理系统

基于SpringBootvue的无偿献血后台管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背…

基于BIM技术建设的重庆来福士广场项目

1. BIM工程应用概况 1.1 工程概况 重庆来福士广场项目位于朝天门广场与解放碑之间&#xff0c;直面长江与嘉陵江交汇口。是集大型购物中心、高端住宅、办公楼、公寓式酒店和酒店为一体的综合体项目。由于本项目钢结构体量大、结构复杂&#xff0c;混凝土标号高、强度大…

树莓派centos7.9(armv7hl)安装最新版宝塔linux面板 2023-0219

内存卡或usb存储器容量建议不小于16GB 1.启用 EPEL 软件源 树莓派安装centos7.9(armv7hl)以及宝塔linux面板. 2023-2-16_mklpo147的博客-CSDN博客 2.使用gcc-6 树莓派centos7.9(armv7hl)安装并切换GCC-6版本. 2023-2-18_mklpo147的博客-CSDN博客 3.更新系统 yum install -y e…

第1讲-初步认识数据库系统(测试题总结)

一、测试题 数据库系统 包含 数据库管理系统 详细版&#xff1a; 数据库管理系统DBMS是数据管理软件&#xff0c;在用户和操作系统之间。 数据库系统DBS由数据库&#xff0c;数据库管理系统&#xff08;及其应用开发工具&#xff09;、应用程序和数据库管理员DBA组成的存储、管…

使用51单片机的GPIO输出占空比可调节的PWM波

一、前言 在一些单片机或微控制器中&#xff0c;通用GPIO可以被配置为产生PWM信号。PWM即脉冲宽度调制&#xff0c;是一种用于模拟输出的技术。它可以通过改变输出信号的脉冲宽度来控制电路中的电平&#xff0c;从而实现对电路的控制。 二、什么是PWM波&#xff1f; PWM波&a…

JavaSE-线程池(5)- 建议使用的方式

JavaSE-线程池&#xff08;5&#xff09;- 建议使用的方式 虽然JDK Executors 工具类提供了默认的创建线程池的方法&#xff0c;但一般建议自定义线程池参数&#xff0c;下面是阿里巴巴开发手册给出的理由&#xff1a; 另外Spring也提供了线程池的实现&#xff0c;比如 Thread…

Flink02:Flink快速上手(Streaming WorldCount)

一、Flink快速上手 使用 &#xff08;1&#xff09;先把Flink的开发环境配置好。 &#xff08;2&#xff09;创建maven项目&#xff1a;db_flink &#xff08;3&#xff09;首先在model中将scala依赖添加进来。 &#xff08;4&#xff09;然后创建scala目录&#xff0c;因为针…

Lesson5---NumPy科学计算库

5.1 多维数组 Python拥有出色的第三方库生态系统在机器学习中&#xff0c;需要把所有的输入数据&#xff0c;都转变为多为数组的形式。score[i, j]二维数组i,j都从0开始 score[5] [85, 72, 61, 92, 80] score[2,5] [[85, 72, 61, 92, 80],[85, 72, 61, 92, 80]] score[30,5…

Linux系统之iptables应用SNAT与DNAT

目录 SNAT 一.SNAT的原理介绍 1.应用环境 2.SNAT原理 3.SNAT转换前提条件 二.开启SNAT 1.临时打开 2.永久打开 三.SNAT的转换 1.固定的公网IP地址 2.非固定的公网IP地址(共享动态IP地址) 四.SNAT实验 1.实验环境准备 2.配置web服务器&#xff08;192.168.100.100…

测试3.测试方法的分类

3.测试分类 系统测试包括回归测试和冒烟测试 回归测试&#xff1a;修改了旧的代码后&#xff0c;重新测试功能是否正确&#xff0c;有没有引入新的错误或导致其它代码产生错误 冒烟测试&#xff1a;目的是确认软件基本功能正常&#xff0c;可以进行后续的正式测试工作 按是否…

什么是 RESTful 风格?

一、什么是 REST &#xff1f; REST即表述性状态传递&#xff08;英文&#xff1a;Representational State Transfer&#xff0c;简称REST&#xff09;是Roy Thomas Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式&#…

游戏开发 - 开发流程 - 收集

1.应用场景 主要用于了解&#xff0c;掌握游戏开发的整个流程。 2.学习/操作 1.文档阅读 复习课 | 带你梳理客户端开发的三个重点-极客时间 2.整理输出 2.1 游戏开发流程 -- 参考 按照游戏开发中的三大模块策划、程序、美术&#xff0c;画了一个图。 开发游戏的时候&#xff…

LeetCode171-Excel表列序号(进制转换问题)

LeetCode171-Excel表列序号1、问题描述2、解题思路&#xff1a;进制转换3、代码实现1、问题描述 给你一个字符串columnTitle,表示Excel表格中得列名称。返回该列名称对应得列序号。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 …

linux shell 入门学习笔记3 shebang

shebang 计算机程序中&#xff0c;shebang指的是出现在文本文件的第一行前两个字符#! 在Unix系统中&#xff0c;程序会分析shebang后面的内容&#xff0c;作为解释器的指令&#xff0c;例如 以#!/bin/sh 开头的文件&#xff0c;程序在执行的时候会调用/bin/sh&#xff0c;也就…

[软件工程导论(第六版)]第5章 总体设计(复习笔记)

文章目录5.1 设计过程5.2 设计原理5.2.1 模块化5.2.2 抽象5.2.3 逐步求精5.2.4 信息隐藏和局部化5.2.5 模块独立5.3 启发规则5.4 描绘软件结构的图形工具5.4.1 层次图5.4.2 HIPO图5.4.3 结构图5.5 面向数据流的设计方法目的 总体设计的基本目的就是回答“概括地说&#xff0c;系…

2.19 索引和事务

一.联合查询面试问题:聚合查询与联合查询的区别聚合查询是行与行之间的数据加工聚合函数 :count,sum,avg...group by 进行分组,指定列的值,相同的记录合并到同一个组,每个组又可以分别进行聚合查询分组还可以指定条件筛选,如果分组之前指定条件 用where,如果对分组之后指定条件…

< CSDN周赛解析:第 28 期 >

CSDN周赛解析&#xff1a;第 27 期&#x1f449; 第一题&#xff1a; 小Q的鲜榨柠檬汁> 题目解析> 解决方案&#x1f449; 第二题&#xff1a; 三而竭> 解析> 解决方案> 拓展知识&#x1f449; 第三题&#xff1a; 隧道逃生> 解析> 解决方案&#x1f449;…

【人工智能AI】四、NoSQL进阶《NoSQL 企业级基础入门与进阶实战》

帮我写一篇介绍NoSQL的技术文章&#xff0c;文章的标题是《四、NoSQL进阶》&#xff0c;不少于3000字。帮我细化到三级目录&#xff0c;使用markdown格式。这篇文章的目录是&#xff1a; 四、NoSQL 进阶 4.1 NoSQL 高可用 4.2 NoSQL 数据安全 4.3 NoSQL 性能优化 4.4 总结 四、…