NIO-概览
NIO-Buffer
NIO-Channel
NIO-Channel接口分析java
原本是想学习Netty的,可是Netty是一个NIO框架,所以在学习netty以前,仍是先梳理一下NIO的知识。经过剖析源码理解NIO的设计原理。微信
本系列文章针对的是JDK1.8.0.161的源码。网络
上一篇介绍了Channel的基本使用,下面对Channel的接口进行分析。并发
SCTP(Stream Control Transmission Protocol)是一种传输协议,在TCP/IP协议栈中所处的位置和TCP、UDP相似,兼有TCP/UDP二者特征。框架
对于SCTP协议这里不详细描述,想了解的同窗能够看下这篇文章
SCTP协议平时用的很少,这里不作具体讨论。异步
NIO使用DatagrmChannel实现了UDP协议的网络通信。socket
下面咱们对各个接口进行分析。tcp
AutoCloseable
和Closeable
分别是自动关闭和主动关闭接口。当资源(如句柄或文件等)须要释放时,则须要调用close方法释放资源。高并发
public interface AutoCloseable { void close() throws Exception; } public interface Closeable extends AutoCloseable { void close() throws IOException; }
Channel
是通道接口,针对于I/O相关的操做,须要打开和关闭操做。
public interface Channel extends Closeable { boolean isOpen(); void close() throws IOException; }
InterruptibleChannel
是支持异步关闭和中断的通道接口。为了支持Thead的interrupt模型,当线程中断时,能够执行中断处理对象的回调,从而关闭释放Channel。
public interface InterruptibleChannel extends Channel { void close() throws IOException; }
关于InterruptibleChannel可中断I/O详细解析能够看一下《JDK源码阅读-InterruptibleChannel与可中断IO》
Interruptible
是线程中断接口,即上面提的Thead的interrupt模型。当线程中断时,则会调用中断操做。
public abstract interface Interruptible { public abstract void interrupt(java.lang.Thread t); } public class Thread implements Runnable { ... public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); } ... }
AbstractInterruptibleChannel
实现了Channel
和InterruptibleChannel
接口。
closeLock
是关闭时的锁open
表示channle是否打开interuptor
为Interruptible
中断回调interrupted
为I/O执行时的线程public abstract class AbstractInterruptibleChannel implements Channel, InterruptibleChannel { ... public final void close() throws IOException { synchronized(this.closeLock) { if (this.open) { this.open = false; this.implCloseChannel(); } } } //具体的Channel实现关闭 protected abstract void implCloseChannel() throws IOException; protected final void begin() { if (this.interruptor == null) { this.interruptor = new Interruptible() { //线程中断时,则会调用该接口关闭Channel public void interrupt(Thread target) { synchronized(AbstractInterruptibleChannel.this.closeLock) { if (AbstractInterruptibleChannel.this.open) { AbstractInterruptibleChannel.this.open = false; AbstractInterruptibleChannel.this.interrupted = target; try { AbstractInterruptibleChannel.this.implCloseChannel(); } catch (IOException x) { } } } } }; } //将线程的blockOn设置为当前interruptor,从而使得线程关闭时能关闭channel blockedOn(this.interruptor); Thread me = Thread.currentThread(); if (me.isInterrupted()) { this.interruptor.interrupt(me); } } protected final void end(boolean completed) throws AsynchronousCloseException { //I/O结束,清除线程blocker blockedOn(null); Thread interrupted = this.interrupted; if (interrupted != null && interrupted == Thread.currentThread()) { interrupted = null; throw new ClosedByInterruptException(); } if (!completed && !open) throw new AsynchronousCloseException(); } static void blockedOn(Interruptible intr) { SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr); } }
AbstractInterruptibleChannel
添加了begin
和end
方法。 在I/O操做开始时会调用begin
,在I/O
操做结束时会调用end
。在begin方法内将中断操做加入到当前线程中。最终会调用到线程的blockOn方法,它会将该中断接口注入到线程中,使得线程中断时能够调用到Channel并释放相关资源。
public void blockedOn(Thread t, Interruptible b) { t.blockedOn(b); }
SelectableChannel
接口声明了Channel是能够被选择的,在Windows平台经过WindowsSelectorImpl
实现,Linux经过EPollSelectorImpl
实现。此外还有KQueue
等实现,关于Selector
具体细节在《NIO-Selector》一文中会介绍。
AbstractSelectableChannel
实现了SelectableChannel
接口。
NetworkChannel
适用于网络传输的接口。
public interface NetworkChannel extends Channel { //绑定地址 NetworkChannel bind(SocketAddress var1) throws IOException; //获取本地地址 SocketAddress getLocalAddress() throws IOException; //设置socket选项 <T> NetworkChannel setOption(SocketOption<T> var1, T var2) throws IOException; //获取socket选项 <T> T getOption(SocketOption<T> var1) throws IOException; //当前通道支持的socket选项 Set<SocketOption<?>> supportedOptions(); }
MulticastChannel
是支持组播接口。
public interface MulticastChannel extends NetworkChannel { void close() throws IOException; MembershipKey join(InetAddress group, NetworkInterface interf) throws IOException; MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) throws IOException; }
SelChImpl
接口用于将底层的I/O就绪状态更新为就绪事件。
public interface SelChImpl extends Channel { FileDescriptor getFD(); int getFDVal(); //更新就绪事件 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk); //设置就绪事件 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk); //将底层的轮询操做转换为事件 void translateAndSetInterestOps(int ops, SelectionKeyImpl sk); //返回channle支持的操做,好比读操做、写操做等 int validOps(); void kill() throws IOException; }
因为UDP支持读写数据,所以还实现了ReadableByteChannel
和WritableByteChannel
接口
public interface ReadableByteChannel extends Channel { int read(ByteBuffer dst) throws IOException; } public interface WritableByteChannel extends Channel { int write(ByteBuffer src) throws IOException; }
ByteChannel
是支持读写的通道。
public interface ByteChannel extends ReadableByteChannel, WritableByteChannel { }
ScatteringByteChannel
则支持根据传入偏移量读,支持根据传入偏移量写GatheringByteChannel
public interface ScatteringByteChannel extends ReadableByteChannel { long read(ByteBuffer[] dsts, int offset, int length) throws IOException; long read(ByteBuffer[] dsts) throws IOException;} public interface GatheringByteChannel extends WritableByteChannel { long write(ByteBuffer[] srcs, int offset, int length) throws IOException; long write(ByteBuffer[] srcs) throws IOException; }
TCP协议除了不支持组播,其余和UDP是同样的,再也不重复介绍。
服务端无需数据读写,仅须要接收链接,数据读写是SocketChannel干的事。所以没有ReadableByteChannel
、WriteableByteChannel
等读写接口
文件比网络协议少了NetworkChannel
、SelChImpl
和SelectableChannel
。SelChImpl
和SelectableChannel
主要是用于支持选择器的,因为网络传输大多数链接时空闲的,并且数据什么时候会到来并不知晓,同时须要支持高并发来链接,所以支持多路复用技术能够显著的提升性能,而磁盘读写则没有该需求,所以无需选择器。
SeekableByteChannel
能够经过修改position支持从指定位置读写数据。
public interface SeekableByteChannel extends ByteChannel { int read(ByteBuffer dst) throws IOException; int write(ByteBuffer src) throws IOException; long position() throws IOException; //设置偏移量 SeekableByteChannel position(long newPosition) throws IOException; long size() throws IOException; //截取指定大小 SeekableByteChannel truncate(long size) throws IOException; }
因为文章篇幅比较长,所以仍是将接口分析和实现分析分开。本篇文章对Channel的接口进行说明,下一篇将对具体的实现进行分析。
微信扫一扫二维码关注订阅号杰哥技术分享
出处:http://www.javashuo.com/article/p-rvmsctkv-gv.html 做者:杰哥很忙 本文使用「CC BY 4.0」创做共享协议。欢迎转载,请在明显位置给出出处及连接。