返回顶部
首页 > 资讯 > 精选 >快速了解Java中NIO核心组件
  • 566
分享到

快速了解Java中NIO核心组件

javanio组件 2023-05-30 17:05:17 566人浏览 薄情痞子
摘要

背景知识同步、异步、阻塞、非阻塞首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下。同步:api调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节)。异步:相对于同步,API调用返回时调用者不知道操作的结果,后面

背景知识

同步、异步、阻塞、非阻塞

首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下。

同步:api调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节)。

异步:相对于同步,API调用返回时调用者不知道操作的结果,后面才会回调通知结果。

阻塞:当无数据可读,或者不能写入所有数据时,挂起当前线程等待。

非阻塞:读取时,可以读多少数据就读多少然后返回,写入时,可以写入多少数据就写入多少然后返回。

对于I/O操作,根据oracle官网的文档,同步异步的划分标准是“调用者是否需要等待I/O操作完成”,这个“等待I/O操作完成”的意思不是指一定要读取到数据或者说写入所有数据,而是指真正进行I/O操作时,比如数据在tcp/IP协议栈缓冲区和JVM缓冲区之间传输的这段时间,调用者是否要等待。

所以,我们常用的read()和write()方法都是同步I/O,同步I/O又分为阻塞和非阻塞两种模式,如果是非阻塞模式,检测到无数据可读时,直接就返回了,并没有真正执行I/O操作。

总结就是,Java中实际上只有同步阻塞I/O、同步非阻塞I/O与异步I/O三种机制,我们下文所说的是前两种,jdk1.7才开始引入异步I/O,那称之为Nio.2。

传统IO

我们知道,一个新技术的出现总是伴随着改进和提升,JavaNIO的出现亦如此。

传统I/O是阻塞式I/O,主要问题是系统资源的浪费。比如我们为了读取一个TCP连接的数据,调用InputStream的read()方法,这会使当前线程被挂起,直到有数据到达才被唤醒,那该线程在数据到达这段时间内,占用着内存资源(存储线程栈)却无所作为,也就是俗话说的占着茅坑不拉屎,为了读取其他连接的数据,我们不得不启动另外的线程。在并发连接数量不多的时候,这可能没什么问题,然而当连接数量达到一定规模,内存资源会被大量线程消耗殆尽。另一方面,线程切换需要更改处理器的状态,比如程序计数器、寄存器的值,因此非常频繁的在大量线程之间切换,同样是一种资源浪费。

随着技术的发展,现代操作系统提供了新的I/O机制,可以避免这种资源浪费。基于此,诞生了JavaNIO,NIO的代表性特征就是非阻塞I/O。紧接着我们发现,简单的使用非阻塞I/O并不能解决问题,因为在非阻塞模式下,read()方法在没有读取到数据时就会立即返回,不知道数据何时到达的我们,只能不停的调用read()方法进行重试,这显然太浪费CPU资源了,从下文可以知道,Selector组件正是为解决此问题而生。

JavaNIO核心组件

1.Channel

概念

JavaNIO中的所有I/O操作都基于Channel对象,就像流操作都要基于Stream对象一样,因此很有必要先了解Channel是什么。以下内容摘自JDK1.8的文档

Achannelrepresentsanopenconnectiontoanentitysuchasahardwaredevice,afile,anetworkSocket,oraprogramcomponentthatiscapableofperfORMinGoneormoredistinctI/Ooperations,forexamplereadingorwriting.

从上述内容可知,一个Channel(通道)代表和某一实体的连接,这个实体可以是文件、网络套接字等。也就是说,通道是JavaNIO提供的一座桥梁,用于我们的程序和操作系统底层I/O服务进行交互。

通道是一种很基本很抽象的描述,和不同的I/O服务交互,执行不同的I/O操作,实现不一样,因此具体的有FileChannel、SocketChannel等。

通道使用起来跟Stream比较像,可以读取数据到Buffer中,也可以把Buffer中的数据写入通道。

快速了解Java中NIO核心组件

当然,也有区别,主要体现在如下两点:

一个通道,既可以读又可以写,而一个Stream是单向的(所以分InputStream和OutputStream)

通道有非阻塞I/O模式

实现

JavaNIO中最常用的通道实现是如下几个,可以看出跟传统的I/O操作类是一一对应的。

FileChannel:读写文件

DatagramChannel:UDP协议网络通信

SocketChannel:TCP协议网络通信

ServerSocketChannel:监听TCP连接

2.Buffer

NIO中所使用的缓冲区不是一个简单的byte数组,而是封装过的Buffer类,通过它提供的API,我们可以灵活的操纵数据,下面细细道来。

与Java基本类型相对应,NIO提供了多种Buffer类型,如ByteBuffer、CharBuffer、IntBuffer等,区别就是读写缓冲区时的单位长度不一样(以对应类型的变量为单位进行读写)。

Buffer中有3个很重要的变量,它们是理解Buffer工作机制的关键,分别是

capacity(总容量)

position(指针当前位置)

limit(读/写边界位置)

Buffer的工作方式跟C语言里的字符数组非常的像,类比一下,capacity就是数组的总长度,position就是我们读/写字符的下标变量,limit就是结束符的位置。Buffer初始时3个变量的情况如下图

快速了解Java中NIO核心组件

在对Buffer进行读/写的过程中,position会往后移动,而limit就是position移动的边界。由此不难想象,在对Buffer进行写入操作时,limit应当设置为capacity的大小,而对Buffer进行读取操作时,limit应当设置为数据的实际结束位置。(注意:将Buffer数据写入通道是Buffer读取操作,从通道读取数据到Buffer是Buffer写入操作)

在对Buffer进行读/写操作前,我们可以调用Buffer类提供的一些辅助方法来正确设置position和limit的值,主要有如下几个

flip():设置limit为position的值,然后position置为0。对Buffer进行读取操作前调用。

rewind():仅仅将position置0。一般是在重新读取Buffer数据前调用,比如要读取同一个Buffer的数据写入多个通道时会用到。

clear():回到初始状态,即limit等于capacity,position置0。重新对Buffer进行写入操作前调用。

compact():将未读取完的数据(position与limit之间的数据)移动到缓冲区开头,并将position设置为这段数据末尾的下一个位置。其实就等价于重新向缓冲区中写入了这么一段数据。

然后,看一个实例,使用FileChannel读写文本文件,通过这个例子验证通道可读可写的特性以及Buffer的基本用法(注意FileChannel不能设置为非阻塞模式)。

FileChannel channel = new RandoMaccessFile("test.txt", "rw").getChannel();channel.position(channel.size());// 移动文件指针到末尾(追加写入)ByteBuffer byteBuffer = ByteBuffer.allocate(20);// 数据写入BufferbyteBuffer.put("你好,世界!\n".getBytes(StandardCharsets.UTF_8));// Buffer -> ChannelbyteBuffer.flip();while (byteBuffer.hasRemaining()) {channel.write(byteBuffer);}channel.position(0);// 移动文件指针到开头(从头读取)CharBuffer charBuffer = CharBuffer.allocate(10);CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();// 读出所有数据byteBuffer.clear();while (channel.read(byteBuffer) != -1 || byteBuffer.position() > 0) {byteBuffer.flip();// 使用UTF-8解码器解码charBuffer.clear();decoder.decode(byteBuffer, charBuffer, false);System.out.print(charBuffer.flip().toString());byteBuffer.compact();// 数据可能有剩余}channel.close();

--结束END--

本文标题: 快速了解Java中NIO核心组件

本文链接: https://lsjlt.com/news/220217.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 快速了解Java中NIO核心组件
    背景知识同步、异步、阻塞、非阻塞首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下。同步:API调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节)。异步:相对于同步,API调用返回时调用者不知道操作的结果,后面...
    99+
    2023-05-30
    java nio 组件
  • Java NIO中四大核心组件的使用详解
    目录一、基础概念1.1 IO和NIO的区别1.2 缓冲区1.3 通道1.4 选择器和选择键二、核心组件2.1 Channel2.2 Buffer2.3 Selector三. 总结Ja...
    99+
    2023-05-20
    Java NIO核心组件使用 Java NIO组件 Java NIO
  • 一篇文章带你了解Java SpringBoot四大核心组件
    目录一、Spring Boot Starter1.1 Starter的应用示例二、Spring Boot Autoconfigure2.1 autoconfigure 简介 三、Sp...
    99+
    2024-04-02
  • 如何快速理解MySQL核心技术?
    如何快速理解MySQL核心技术?MySQL是一种常用的关系型数据库管理系统,广泛应用于各种应用程序和网站开发中。理解MySQL的核心技术对于数据库开发和管理非常关键。本文将介绍一些快速理解MySQL核心技术的方法和建议。首先,了解MySQL...
    99+
    2023-10-22
    MySQL 数据库 核心技术
  • 一文让你了解SpringCloud五大核心组件
    🏆今日学习目标: 🍀SpringCloud五大核心组件 ✅创作者:林在闪闪发光 ⏰预计时间:30分钟 🎉个人主页:林在闪闪发光的个人主页  🍁林在闪闪发光的个人社区,...
    99+
    2023-09-11
    spring cloud spring java
  • 快速了解Java中ThreadLocal类
    最近看Android FrameWork层代码,看到了ThreadLocal这个类,有点儿陌生,就翻了各种相关博客一一拜读;自己随后又研究了一遍源码,发现自己的理解较之前阅读的博文有不同之处,所以决定自己写篇文章说说自己的理解,希望可以起到...
    99+
    2023-05-30
    java threadlocal ava
  • Java日志的核心组件是什么
    本篇内容介绍了“Java日志的核心组件是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java日志基础Java使用了一种自定义的、可扩展...
    99+
    2023-06-17
  • 深入了解Java核心类库--Objects类
    目录1 Objects1.1 Objects方法1.2 Objects常用方法1.2.1 equals(Object a, Object b)1.2.2 isNull(Object ...
    99+
    2024-04-02
  • 深入了解Java核心类库--Math类
    目录Java常用类库Math一、Field Summary二、Method Summary2.1 常用方法2.1.1 部分方法源码2.2 算数运算2.3 三角函数2.4 其他不常用方...
    99+
    2024-04-02
  • 深入了解Java核心类库--Arrays类
    目录Java常用类库Arrays一、常用方法1.1 toString1.2 Sort1.2.1 sort​(T[] a, int fromIndex, int toInd...
    99+
    2024-04-02
  • 深入了解Java核心类库--String类
    目录一、 简介零碎知识点字符串常量池堆在逻辑上的划分二、 创建对象2.1.1 直接引用常量区2.1.2 使用构造方法2.1.3 两种实例化方法的区别三、常用方法总结一、 简介 零碎知...
    99+
    2024-04-02
  • 如何快速了解Java中的IO流
    这篇文章主要介绍“如何快速了解Java中的IO流”,在日常操作中,相信很多人在如何快速了解Java中的IO流问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何快速了解Java中的IO流”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • 深入了解Java核心类库--泛型类
    目录1.1 泛型的使用1.1.1 泛型类1.1.2 泛型接口1.1.3 泛型方法1.1.4 tips 1.2 泛型限制类型1.3 通配符?1.3.1 上界限定1.3.2 下...
    99+
    2024-04-02
  • JavaScript编程思维导图:快速理解JavaScript核心知识
    JavaScript编程思维导图 1. JavaScript介绍 JavaScript是一种基于文本的编程语言,用于创建交互式网页、游戏和其他应用程序。它与HTML和CSS一起使用,构成了现代网页的基础。JavaScript可以用来添加各...
    99+
    2024-02-09
    JavaScript, 编程, 思维导图, 核心知识
  • Tomcat核心组件及应用架构详解
    目录Web容器是什么?HTTP的本质HTTP请求响应实例Cookie和SessionServlet规范Servlet容器Web应用扩展机制一、Tomcat各组件认知2.Tomcat各...
    99+
    2024-04-02
  • 如何理解Kubernetes核心概念与组件
    本篇内容主要讲解“如何理解Kubernetes核心概念与组件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Kubernetes核心概念与组件”吧!Kub...
    99+
    2024-04-02
  • Spring Cloud原理以及核心组件详解
    目录概述一、业务场景介绍二、Spring Cloud核心组件:Eureka三、Spring Cloud核心组件:Feign四、Spring Cloud核心组件:Ribbon五、Spr...
    99+
    2023-03-21
    Spring Cloud原理详解
  • flutter图片组件核心类源码解析
    目录导语问题Image的核心类图及其关系网络图片的加载过程网络图片数据的回调和展示过程补上图片内存缓存的源码分析如何支持图片的磁盘缓存总结导语 在使用flutter 自带图片组件的过...
    99+
    2023-05-16
    flutter图片组件核心类 flutter图片组件源码解析
  • Docker核心组件之联合文件系统详解
    目录1. 联合文件系统的定义2. 配置 Docker 的 AUFS 模式3. AUFS 工作原理3.1 AUFS 如何存储文件3.2 AUFS 如何工作4. AUFS 演示4.1 准...
    99+
    2024-04-02
  • 深入了解Java核心类库--BigDecimal和System类
    目录BigDecimal 类一、 概述常用字段常用构造方法常用方法System类三个成员变量arraycopy​(Object src, int srcPos, Obje...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作