网络上有很多写NIO的文章, 但是大多讲的网络那一块, 我想像前俩次那样先从磁盘IO讲起, 然后慢慢过渡到网络IO, 再慢慢地进入socket, epoll, 能有这样一个循序渐进的过程.
仍然从一个读文件的小demo程序开始入手分析
public class TestFileChannel {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("./10bytes.txt");
FileChannel channel = inputStream.getChannel();
// 分配一个10byte的ByteBuffer.ByteBuffer byteBuffer = ByteBuffer.allocate(10);
channel.read(byteBuffer);
// TODO close}
}
看一下getChannel()实现
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, true, false, this);
}
return channel;
}
}
getChannel()的源码很简单, 就是直接生成了一个FileChannelImpl实例
// 下列内容在openjdk-jdk8u-jdk8u/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
// Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() public static FileChannel open(FileDescriptor fd, String path,
boolean readable, boolean writable,
Object parent)
{
return new FileChannelImpl(fd, path, readable, writable, false, parent);
}
通过上面的UML类图, 可以看到FileChannel主要是定义了一些抽象方法, 真正的读写实现是在FileChannelImpl中实现的.
// 下列内容在openjdk-jdk8u-jdk8u/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
public int read(ByteBuffer dst) throws IOException {
ensureOpen();
if (!readable)
throw new NonReadableChannelException();
synchronized (positionLock) {
int n = 0;
int ti = -1;
try {
begin();
ti = threads.add();
if (!isOpen())
return 0;
do {
n = IOUti