`
QING____
  • 浏览: 2234176 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

NIO-Channel相关接口详解

 
阅读更多

 

一.Channel相关接口(概述):

NIO中核心的API,它被底层操作封装,提供了数据进行NIO操作的"途径",可以配合Selector实现多路IO复用/非阻塞操作.Channel(通道)表示实体(例如硬件设备,文件,网络socket等)的开放链接.Channel与其实体关联,并具有相同的状态,例如关闭或者开启.Channels可以是异步的(noblocking),可中断的(inerruptable).

Channel接口是最顶级的接口.其子接口列表如下:

  1. ReadableByteChannel:可以将内容读入缓冲区,此接口具有一个read(ByteBuffer bb)方法.
  2. ScatteringByteChannel:继承自ReadableByteChannel,可以讲内容依次读入一个或多个缓存区,此接口有一个方法read(ByteBuffer[] dts).
  3. WritableByteChannel:可以将缓冲区内如写入通道,此接口有一个方法write(ByteBuffer bb).
  4. GatheringByteChannel:继承自WritableByteChannel,可以讲多个缓冲区内容依次写入到通道中.此接口有一个方法write(ByteBuffer[] dts).
  5. ByteChannel:一个综合接口,"字节操作渠道",此接口继承ReadableByteChannel/WritableByteChannel.此接口本身无定义方法.

Channels是一个辅助类,提供了多个基于channel操作的util方法.

FileChannel:文件操作的通道,支持向文件进行读取/写入操作FileLock:对文件或者文件区域进行锁定.

MappedByteBuffer:直接映射缓冲区.FileChannel支持连接到文件通道中读取/写入数据,以及查询文件中指定区域(region)的数据.已经在这个文件或者region上锁定的功能(mapping),获取一个FileLock实例.

而且还提供了将文件数据直接映射到内存的方法,即MappedByteBuffer.目前,FileInputStream/FileOutputStream/RandomAccessFile类添加了getChannel方法.这个方法可以获取底层和文档操作绑定的channel.

 

二.多路复用/非阻塞IO通道(概述):

SelectableChannel: 可被选择的通道,能够被Selector支持,是NIO + selector支持的通道."可被选择通道"继承自InterruputableChannel.即为可中断通道.它也是基于网络NIO channel的父接口.我们熟悉的SocketChannel,ServerSocketChannel,DatagramChannel也是扩展自它.

Pipe.SinkChannel,Pipe.SourceChannel这两个基于"管道模式"的通道,也是SelectableChannel.但是Pipe更加特殊.

Selector即为"选择器",是提供多路复用的"操作事件控制"类.

SelectionKey即为"选择键",是channel与selector建立关联的"凭证"或者说是"channel就绪事件"的持有者.

Pipe:一种特殊的channel,形成单向管道的的两个通道,SourceChannel和SinkChannel.

Selector + SelectableChannel + SelectionKey,三者各司其职,并有效配合,最终支撑了NIO数据通讯...

一个channel需要register到指定的一个Selector,此后就可以在此selector上获得和当前channel有关的就绪事件(即SelectionKey).如果某个通道已准备就绪,则将注册是所返回的key添加到选择器的已选择键集合中(selectedKeySet).为了确定哪个通道已准备好执行哪些操作,那么可以通过检查该键集合和其中的key(通常我们采用遍历的方式).selectionKey持有channel信息.

SelectionKey只是channel就绪状态,它本身并不负责对channel的实际操作,因此需要手动去处理这些事件(忽略或者执行).

三.Channel接口

Channel接口是顶级接口,用于控制I/O操作连接,目前已知的文件IO/网络IO都可以获取.

Channel表示到实体(网络设备,文件,Socket等有IO操作)的程序组件的开放连接.我们认为Channel创建成功后,本身持有IO操作的Input和Output.

Channel接口仅仅实现了Closable接口,即任何通道需要具备"开启"状态,以及需要应用手动关闭.

Channel本身底层仍然基于普通的IO,因此channel在多线程环境中是线程安全的.

注意,在Socket操作中,在多个线程中,同时进行进行数据read/write时,数据的操作顺序可能将不能得到保证.所以如果想确保数据发送/读取数据的顺序性,要么对数据进行队列化,要么对操作队列化.(主要原因是底层InputStream/OutputStream非同步操作的).

 

四.WritableByteChannel:可写字节Channel,此接口提供了向通道写入字节序列的能力.在任意给定时刻,一个可写入通道上只能进行一个写入操作。如果某个线程在通道上发起写入操作,那么在第一个操作完成之前,将阻塞其他所有试图发起另一个写入操作的线程。其他种类的 I/O 操作是否继续与写入操作并发执行则取决于该通道的类型。这一点有别于Socket.WritableByteChannel只有一个方法:

  • public int write(ByteBuffer src) throws Exception:write操作,在NIO中只支持ByteBuffer.此方法将制定的字节序列,写入到channel中.注意在非阻塞模式下,write操作并不保证将src中所有的内容都写入后才返回,此方法返回写入成功的字节数,有可能为0,但总是不大于byteBuffer.remaining().在阻塞模式下,write将所有的字节写入完成后,返回.参见Channels.WritableByteChannelImpl

五.ReadableByteChannel:可读字节Channel,同WritableByteChannel对称.任何时刻,只能有一个read操作在此通道上.如果某个线程在通道上发起读取操作,在此操作完成之前,其他线程对此通道的read操作将会被阻塞.参见Channels.ReadableByteChannelImpl;此接口只有一个方法:

  • public int read(ByteBuffer dst) throws Exceoption:从通道中读取数据到buffer中.返回读取到的字节数,可能为0;读取数据长度最大为buffer.capacity().如果此时通道已经到达流的结尾,则返回-1.在非阻塞模式下,read方法可能读取0个字节也会返回.在阻塞模式下,read方法在则阻塞,在至少读取一个字节后可以返回.

六.ByteChannel:一个相对高层的接口,此接口是一个标记接口,没有定义API方法.此接口继承了WritableByteChannel和ReadableByteChannel.常用的FileChannel和SocketChannel都直接实现了此接口.

七.ScatteringByteChannel:"分散"读取操作,是一个高级接口,支持一个通道中一次read操作的结果"分散"给多个byteBuffer.此接口继承自ReadableByteChannel;此接口增加一个特殊的方法:

  • public long read(ByteBuffer[] dsts) throws IOException:将字节序列依次读入指定的缓冲区数组.此接口终于提供给我一种解决方案:一次read的数据分散到过个buffer,然后在多线程使用.或者将一个相对较大的buffer,以多个较小buffer的方式操作.

八.GatheringByteChannel:"集中"写入操作,是一个高级接口,支持一个通道中一次write操作中,将指定的多个ByteBuffer数据依次写入通道.此接口继承自WritableByteChannel.

此接口新增一个特殊的方法:

  • public long write(ByteBuffer[] srcs) throws Exception:返回写入成功的字节个数,可能为0.在非阻塞模式下,有可能返回0或者其他任意不大于srcs的remaning()之和的数字..在阻塞模式下,只有当所有字节都写入,尚可返回.buffer数组将会被依次写入.

九.InterruptibleChannel:"可中断"通道,即此通道可以被异步关闭和中断.

实现此接口的通道是可被异步关闭的,如果某个线程阻塞于InterruptibleChannel的I/O操作中,另一个线程可以调用该通道的close方法.此时被阻塞的线程将会受到AsynchronousCloseException.实现此接口的通道是可被中断的,如果某个线程阻塞于InterruptibleChannel的I/O操作中,则另一个线程可调用该阻塞线程的interrupt方法.这将导致channel被关闭,已阻塞线程将收到ClosedByInterruptException,并且设置阻塞线程的状态为中断.如果已设置某个线程的中断状态,此后它在通道上调用某个阻塞的I/O操作,则该通道将会被关闭且该线程将立即受到ClosedByInterruptException.此接口没有特殊的方法,只是重新定义了close()方法.

此处描述一下"可中断"通道是如何实现异步关闭和中断响应的:参见AbstractInterruptibleChannel

  1. 对于任何通过channel方式read和write操作(参见Channels.WritableByteChannelImpl,Channels.ReadableByteChannelImpl),都将被同步,在read()方法中,需要对一个Object readLock进行同步,在write()方法中需要对一个Object writeLock进行同步.因此对于一个channel在多线程中read(或者write)将会被序列化.
  2. read或者write操作中,在实际的IO操作之前,都会执行AbstractInterruptibleChannel.begin()方法:此方法做的一件事情,就是向Thread.currentThread()注册一个支持异步回调的interruptor对象,即赋值给Thread中Interruptible blocker属性.实际IO操作完毕之后(例如:outputStream.write()...),read或者write方法中将会调用AbstractInterruptibleChannel.end(boolean)方法:此方法将会首先解除Thread中的blocker(即赋值为null),然后检测channel是否被"中断"(每个channel实例,都有一个interrupted属性),如果是,将抛出ClosedByInterruptException.然后检测,当前Channel是否被关闭(channel中有open属性,默认为true),如果是,抛出AsynchronousCloseException.(即被interrupt之后,将会在blocker执行close方法,所以此后channel将不可用)
  3. 执行channel.close()方法时,将会导致其open属性置为false.因此在AbstractInterruptibleChannel.end()方法中检测open属性时,将会抛出相应的异常.难道这就是异步关闭??????好吧,我们简单的认为,当线程"close"了通道,只有其他线程在read或者write时,将会在此后的某个时间被告知"已关闭".根据"异步"的概念,这也可以被认为"异步"吧.
  4. Thread.interrupt()方法中,会对channel注册的interruptor对象进行检测,如果发现此对象不为null,则触发interruptor执行回调方法.回调方法,主要是讲此channel的interrupt属性改为true,open改为false.此后再次channel上调用read或者write时将会触发对interrupt和open属性的校验,以抛出异常.
  5. begin()方法中,仍然会对Thread.currentThead().isInterrupted()校验,如果当前线程已经被"中断",则直接抛出异常..
  6. 经上所述,一个channel的中断和关闭,与Thread控制,形成了密切的回环控制.
  7. 支持noblocking的NIO Channel都实现了此接口.例如SocketChannel,ServerSocketChannel,DatagramChannel,Pipe.SinkChannel,Pipe.SourceChannel等.
分享到:
评论

相关推荐

    java网络编程NIO视频教程

    05-Java NIO-Channel-FileChannel详解(一).mp4 06-Java NIO-Channel-FileChannel详解(二).mp4 07-Java NIO-Channel-Socket通道-概述.mp4 08-Java NIO-Channel-ServerSocketChannel.mp4 09-Java NIO-Channel-...

    Java NIO实战开发多人聊天室

    05-Java NIO-Channel-FileChannel详解(一).mp4 06-Java NIO-Channel-FileChannel详解(二).mp4 08-Java NIO-Channel-ServerSocketChannel.mp4 09-Java NIO-Channel-SocketChannel.mp4 10-Java NIO-Channel-...

    JAVA IO-NIO 详解

    NIO的核心组件包括Channel(通道)、Buffer(缓冲区)和Selector(选择器)。Channel是数据传输的通道,它替代了传统IO中的流;Buffer是数据的容器,它可以在Channel和程序之间进行数据的读写操作;Selector则用于...

    详解java NIO之Channel(通道)

    主要介绍了详解java NIO之Channel(通道)的相关资料,文中讲解非常详细,示例代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

    JAVA-NIO之Socket/ServerSocket Channel(详解)

    下面小编就为大家带来一篇JAVA-NIO之Socket/ServerSocket Channel(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    详解java nio中的select和channel

    主要介绍了java nio中的select和channel

    Java 高并发八:NIO和AIO详解

    本文主要介绍Java 高并发NIO和AIO 的知识,这里整理了详细的资料,并详细介绍了 1. 什么是NIO 2. Buffer 3. Channel 4. 网络编程 5. AIO的知识,有需要的小伙伴可以参考下

    精通并发与netty视频教程(2018)视频教程

    51_NIO零拷贝彻底分析与Gather操作在零拷贝中的作用详解 52_NioEventLoopGroup源码分析与线程数设定 53_Netty对Executor的实现机制源码分析 54_Netty服务端初始化过程与反射在其中的应用分析 55_Netty提供的Future与...

    精通并发与 netty 视频教程(2018)视频教程

    32_IO体系架构系统回顾与装饰模式的具体应用 33_Java NIO深入详解与体系分析 34_Buffer中各重要状态属性的含义与关系图解 35_Java NIO核心类源码解读与分析 36_文件通道用法详解 37_Buffer深入详解 38_NIO堆外内存与...

    Java 基础核心总结 +经典算法大全.rar

    -、Iterator Iterable ListIterator 二、Map 和 Collection 接口Map 集合体系详解 HashMap LinkedHashMap TreeMap WeakHashMap Hashtable Collection 集合体系详解 Set 接口 AbstractSet 抽象类SortedSet 接口...

    精通并发与netty 无加密视频

    第51讲:NIO零拷贝彻底分析与Gather操作在零拷贝中的作用详解 第52讲:NioEventLoopGroup源码分析与线程数设定 第53讲:Netty对Executor的实现机制源码分析 第54讲:Netty服务端初始化过程与反射在其中的应用分析...

    Java CP/IP Socket编程

    4.1.5 系统管理调度:Executor接口..........89 4.2 阻塞和超时..........91 4.2.1 accept(),read()和receive()..........91 4.2.2 连接和写数据..........92 4.2.3 限制每个客户端的时间..........92 4.3 多...

    JAVA核心知识点整理(有效)

    1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................

    疯狂JAVA讲义

    9.2 系统相关 319 9.2.1 System类 319 9.2.2 Runtime类 321 9.3 常用类 322 9.3.1 Object类 322 9.3.2 String、StringBuffer和StringBuilder类 322 9.3.3 Math类 327 9.3.4 Random类 328 9.3.5 BigDecimal类...

Global site tag (gtag.js) - Google Analytics