Java学习(BIO编程、NIO、AIO及其区别)

BIO编程

使用统一接口进行操作,具体实现细节无关

字节流

InputStream和OutputStream,都实现了Closeable接口,所以支持try-resources

InputStream操作用于实现数据的读取操作

  • read():int 注意这里只是读取一个字节,0-255之间,-1表示流结束

  • read(byte[]):int 返回值表示读取的具体字节个数,-1流结束

  • close():void 关闭流

  • 另外不重要的方法 read(byte[],int,int) available() skip(long)

OutputStream操作方法用于实现数据的写出操作

  • write(int):void 写出一个字节,int的低8位

  • write(byte[]具体数据,int起始下标,int长度):void

  • close():void 关闭流

  • 不重要的方法write(byte[])、flush()

字符流

顶级父抽象类Reader和Writer,一次一字符的操作,实现了Closeable接口。如果涉及中文信息,则需

要考虑编码字符集的问题,如果编码字符集错误,则显示乱码

Reader用于封装字符读取操作

  • read():int 返回读取到的字符数据,0-65535 2B,返回-1 表示流末尾

  • read(char[]):int 返回读取的字符个数,流结束返回-1

  • close():void 关闭流

Writer用于封装字符写出操作

  • write(int):void 写出低16位

  • write(char[]数据,int起始下标,int写出的字符数):void

  • close():void 关闭流,释放资源

  • write(String):void 写出一个字符串内容到输出流中

节点流
类型字符流字节流
文件FileReader和FileWriterFileInputStream和FileOutputStream
数组CharArrayReader和CharArrayWriterByteArrayInputStream和ByteArrayOutputStream
字符串StringReader和StringWriter
线程通讯使用的管道PipedReader和PipeWriterPipedInputStream和PipeOutputStream
文件流

FileInputStream和FileReader用于从一个文件中读取数据;FileOutputStream和FileWriter用于向一个

文件中写出数据

FileInputStream文件输入字节流,FileReader文件输入字符流,用法类似

  • FileInputStream(“文件名称”),如果文件不存在则FileNotFoundException

  • FileInputStream(File)

FileOutputStreram文件输出字节流,FileWriter文件输出字符流,用法类似

  • FileOutputStream(“文件名称”);如果文件不存在,则自动创建;如果文件存在则执行覆盖原文件内容

  • FileOutputStream(“文件名称”,boolean是否采用追加方式);如果文件不存在,则自动创建;如果文件存在并且Boolean参数为true则表示采用追加的方式处理

NIO

NIO是采用内存映射文件的方式处理输出输出,可以将文件或者文件的一段区域映射到内存中,然后就

可以像访问内存一样来访问文件,所以进行输入输出的速度比BIO快的多

  • BIO是同步阻塞式;NIO是同步非阻塞式

  • BIO是面向流的,NIO是面向缓冲区的

  • NIO是一个线程从某个通道发送读取请求时,仅仅获取当前可以用的数据不会保持阻塞等待

NIO基础

NIO中由3个核心对象Channel通道、Buffer缓冲和Selector多路复用器

  • Channel是对传统输入输出系统的模拟,可以通过map方法将一块数据映射到内存中

  • Buffer本质上就是一个数组,发送到Channel中的所有数据都先放入到buffer中,针对基本数据类型提供7种不同的buffer,没有boolean类型没有

  • selector多路复用器,针对事件进行选择,实现一对多的连接效果

Buffer抽象类

Buffer主要作用就是用于转入数据,然后输出数据。最基本的实现是ByteBuffer,可以在字节数组上进行 get/set操作;另外针对基本数据类型,系统提供了7种具体的实现,例如CharBuffer、ShortBuffer、DoubleBuffer

  • 静态方法allocate(int capacity)创建一个容积为capacity的xxxBuffer对象

buffer有3个核心概念:容积capacity、界限limit和位置position

  • capacity表示该buffer的最大数据容量,一旦创建对象则不能修改

  • limit表示位于limit之后的数据既不可读,也可写

  • position表示下一次可读写的索引位置

  • mark标记特定位置,需要注意只能在0到position之间

常用方法

  • capacity():int 返回buffer的容积值

  • hasRemaining():boolean 判断是否还有数据可以进行处理

  • remaing():int 获取position当前位置和limit界限之间的元素个数

  • position():int 返回当前的操作位置

  • mark():Buffer 设置标记位置,已被后面重返这个位置

  • reset():Buffer 将位置position重新返回到mark所在为位置

  • rewind():Buffer 将position重新设置到0,并取消mark标记

  • put(obj) :xxxBuffer 用于向buffer中添加数据

  • get():xxx 用于从buffer中获取数据

Channel通道

Channel可以直接将文件的部分或者全部映射到 buffer中。注意不能直接访问Channel中的数据,包括读写都不行,Channel只能与buffer进行交互

  • 所有的Channel不应该使用构造器来直接创建,而是通过传统的InputStream\OutputStream的getChannel方法获取。一般使用FileInputStream和FileOutputStream中的 getChannel获取
selector

是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel通道的状态是否处于可读、可写。如此可以实现单线程管理多个channels也就是可以管理多个网络链接。

使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销

  • FileChannel不能切换为非阻塞模式,更准确的来说是因为FileChannel没有继承SelectableChannel

  • 多用于网络应用编程中

基本用法
  1. Selector的创建。通过调用Selector.open()方法创建一个Selector对象

    Selector selector = Selector.open(); 
    
  2. 注册Channel到Selector

    channel.configureBlocking(false); 
    SelectionKey key = channel.register(selector, Selectionkey.OP_READ); 
    

    Channel必须是非阻塞的。

  3. 轮询方式获取选择器上的状态值

    while(selector.select()>0){ 
    	Iterator<SelectionKey> it=selector.selectedKeys().iterator(); 
    	... 
    } 
    
Charset字符集

所有的文件底层都是二进制数据存储的,字符文件是系统将底层的二进制序列转换为字符,这里一定会涉及编码字符集和对应的编码器和解码器

  • 将明文的字符序列转换为计算机理解的二进制序列称为编码

  • 将二进制序列转换为明文字符串称为解码

Charset类

Charset.availableCharsets()获取当前JDK所支持的所有字符集

//获取当前JDK所支持的所有字符集 
SortedMap<String, Charset> sm = Charset.availableCharsets(); 
for(String tmp:sm.keySet()) { 
	System.out.println(tmp); 
}

字符串别名:

  • GBK简体中文 GB2312

  • ISO-8859-1 拉丁文 欧洲的所有编码

  • UTF-8 变长编码,支持中文,实际上是Unicode编码的一种实现

构建对象

Charset c=Charset.forName("GBK");
文件锁FileLock

文件锁用于阻止多个进程并发修改同一个文件

在NIO中提供了FileLock支持文件锁定功能

  • 在FileChannel中提供了lock/tryLock方法可以获取文件锁对象以实现锁定文件,避免同时修改

    • lock()用于锁定某个文件,如果无法获取文件锁,则程序一直阻塞等待
    • tryLock()是尝试锁定文件,如果可以锁定则直接返回该文件锁,如果不能锁定也是立即返回null,不会出现阻塞等待
  • 锁可以是排它锁或者共享锁,shared=true表示共享,允许多个进程同时读取文件,但是会阻止其它进程获取该文件的排他锁

文件锁是建议性质,不是强制性。

AIO

异步非阻塞式

JDK7新增了一些和文件、网络IO相关的API,AIO最大的特性就是异步处理能力,一般用于网络编程和大文件IO处理中。AIO其实就是一种在读写操作结束之前允许执行其它操作的IO处理,等读写执行完毕自动通知调用后续处理

提供了3个异步处理通道

  • AsynchronousFileChannel用于文件的异步读写

  • AsynchronousSocketChannel用于socket客户端异步读写

  • AsynchronousServerSocketChannel用于serverSocket服务端异步读写

异步无非是通知系统做一件事情,然后自己做其它事情,异步调用如何进行后续处理,处理方式有2种:

  • 将来式,主线程发起异步请求,轮询并等待结果使用

  • 回调式,异步回调

AIO的具体实施需要充分调用操作系统OS参与,IO需要OS支持,并发也同样需要OS支持,所以OS不同时执行执行性能方便差异会比较明显,因此在具体的应用种AIO使用并不是很广泛

BIO vs NIO vs AIO

概念

BIO:同步阻塞,实现模式为一个连接一个线程,就是客户端连接请求时,服务器需要启动一个线程进行处理

NIO:同步非阻塞,实现模式为一个连接一个线程,客户端发起请求时会注册到selector多路复用器上,多路复用器会轮询所有有IO请求时才启动一个线程进行处理

AIO:异步非阻塞,一个有效请求一个线程,客户端IO请求都是由OS操作系统先完成了再通知服务器应用启动线程进行处理

场景
  • BIO适用于连接数目比较小且固定的架构,这种方式对服务器资源要求较高,并发局限于应用中,JDK1.4以前的唯一选择,但是程序直观、简单且易于理解

  • NIO适用于连接数目比较多且连接时间较短的架构中,例如聊天服务器,并发局限于当前应用中,编程相对比较复杂,从JDK1.4开始支持

  • AIO适用于连接数目多且连接时间长的架构中,例如相册服务器,可以充分调用OS参与同步IO处理,而且proactor用于异步IO中

区别
  • 同步阻塞:用户进程发起一个IO操作请求后,必须等待IO操作完成后,用户进程才能继续运行后续操作,否则用户进程阻塞等待

  • 同步非阻塞:用户进程发起一个IO操作请求后可以返回做其它事情,但是用户进程需要不时询问IO操作是否已经就绪,这里会造成不必要的CPU资源浪费

  • 异步非阻塞:用户进程发起一个IO操作请求后可以立即返回做其它事情,等到IO操作真正完成后,应用程序会收到IO操作完成的通知,此时用户进程只需要对数据进行处理即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值