HotSpot IO与NIO

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。ava IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

一.IO

Java的IO是面向流的,以输入输出流为基础,通过装饰器模式衍生处多种API,以适应复杂的上层应用需求。字节/字符流,文件/对象流等。进一步的,IO层面也提供了文件系统API,以及字节流和字符流的转换API。

public class Hello{
    public static void main(String[] args){
        try {
            String hello= new String( "hello word!");
            byte[] byteArray= hello.getBytes();
            File file= new File( "/home/charlie/test.txt");
            //字节流断点调试
            OutputStream os= new FileOutputStream(file);
            os.write( byteArray);
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

java\io\FileOutputStream.java

class FileOutputStream extends OutputStream{
	 public void write(byte b[]) throws IOException {
        writeBytes(b, 0, b.length, fdAccess.getAppend(fd));
    }
     private native void writeBytes(byte b[], int off, int len, boolean append)
        throws IOException;
}

jdk/src/java.base/unix/native/libjava/FileOutputStream_md.c

JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
    jobject this, jbyteArray bytes, jint off, jint len, jboolean append) {
    writeBytes(env, this, bytes, off, len, append, fos_fd);
}

在虚拟机层面HotSot提供了与各操作系统IO流读写接口,使得上层API不必考虑诸多细节。
在这里插入图片描述

二.NIO

Java的NIO是基于缓冲和通道的。相比于IO,NIO提供了各类channel和缓冲API来满足上层应用的复杂需求。此外还提供了charset字符编解码集。和基于NIO的文件系统API。

public class Hello{

    public static void main(String[] args){
        
        try {
            //通道
            RandomAccessFile aFile = aFile = new RandomAccessFile("data/nio-data.txt", "rw");
            FileChannel inChannel = aFile.getChannel();
            //缓冲
            ByteBuffer buf = ByteBuffer.allocate(48);
            //读缓冲
            int bytesRead = inChannel.read(buf);
            while (bytesRead != -1) {

                buf.flip();

                while(buf.hasRemaining()){
                    System.out.print((char) buf.get());
                }

                buf.clear();
                bytesRead = inChannel.read(buf);
            }
            aFile.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

java.nio提供了通道,文件系统,字符集SPI。

在这里插入图片描述

java\io\RandomAccessFile.java

public final FileChannel getChannel() {
        FileChannel fc = this.channel;
        this.channel = fc = FileChannelImpl.open(fd, path, true,
                        rw, false, this);
        return fc;
    }

sun\nio\ch\FileChannelImpl.java

 public static FileChannel open(FileDescriptor fd, String path,
                                   boolean readable, boolean writable,
                                   boolean direct, Object parent)
    {
        return new FileChannelImpl(fd, path, readable, writable, direct, parent);
    }

而sun.nio提供了channel,字符集,文件系统更详细的实现。如FileChannel 的实现 FileChannelImpl

在这里插入图片描述

sun\nio\ch\FileChannelImpl.java

public int read(ByteBuffer dst) throws IOException {
        ensureOpen();
         try {
                beginBlocking();
                ti = threads.add();
                if (!isOpen())
                    return 0;
                do {
                    n = IOUtil.read(fd, dst, -1, direct, alignment, nd);
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
                return IOStatus.normalize(n);
            } finally {
                threads.remove(ti);
                endBlocking(n > 0);
                assert IOStatus.check(n);
            }
    }

sun\nio\ch\IOUtil.java

static int read(FileDescriptor fd, ByteBuffer dst, long position,
                    boolean directIO, int alignment, NativeDispatcher nd)
        throws IOException
    {
          try {
            int n = readIntoNativeBuffer(fd, bb, position, directIO, alignment,nd);
            bb.flip();
            if (n > 0)
                dst.put(bb);
            return n;
        } finally {
            Util.offerFirstTemporaryDirectBuffer(bb);
        }
    }

sun\nio\ch\IOUtil.java

 private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
                                            long position, boolean directIO,
                                            int alignment, NativeDispatcher nd)
        throws IOException
    {
        int n = 0;
        if (position != -1) {
            n = nd.pread(fd, ((DirectBuffer)bb).address() + pos, rem, position);
        } else {
            n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
        }
        if (n > 0)
            bb.position(pos + n);
        return n;
    }

jdk/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java

class SocketDispatcher extends NativeDispatcher
{

    int read(FileDescriptor fd, long address, int len) throws IOException {
        return FileDispatcherImpl.read0(fd, address, len);
    }
}

jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c

JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz,
                             jobject fdo, jlong address, jint len)
{
    jint fd = fdval(env, fdo);
    void *buf = (void *)jlong_to_ptr(address);

    return convertReturnVal(env, read(fd, buf, len), JNI_TRUE);
}

除此之外,NIO的Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便,要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值