谈谈BIO、NIO、AIO

1.JAVA中的IO

IO 是 Input/Output 的简称,经常写作 I/O 即输入/输出。通常指数据在内存和硬盘之间的输入和输出。

输入/输出是信息处理系统与外部世界之间的通信,比如计算机和人类之间。

输入是系统接收的信号或数据,输出则是从其发送的信号或数据。

JAVA 中提供了一些 API,可以提供开给发者来读写外部数据或文件,通常称这些 API 为 Java IO。

随着JAVA 的不断发展,目前有三种 IO ,分别是 BIO、NIO、AIO。

2.BIO

BIO 全称 Block-IO 是一种同步阻塞的通信模式。是一个比较传统的通信方式,该模式实现起来简单方便,但通信耗时并且并发处理能力低下。

3.NIO

即 JAVA 中的 NIO( Non-Block IO ),是一种非同步阻塞的通信模式。它是 JAVA SE 1.4 版本之后针对网络传输效能优化的新功能。

NIO 与原来的 I/O 一样, 他们之间最重要的区别是数据打包和传输方式上的不同。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。

面向流的 I/O 系统以一次一个字节的方式处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。

面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 实现起来没有面向流的简单。

4.AIO

即 JAVA 中的 AIO(Asynchronous IO),是异步非阻塞的通信模式。

在 NIO 的基础上引入了异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。

5.三种IO的区别

5.1 业务场景

用洗衣机洗衣服的场景来举例:

  • BIO同步阻塞模式:这种模式下,我们是一直坐在洗衣机面前盯着,等衣服洗好。
  • NIO同步非阻塞模式:这种模式下,我们不用坐在洗衣机面前等,而是去干其他事,然后每隔几分钟看一下洗衣机有没有洗好。阻塞VS非阻塞:人是否坐在洗衣机前面一直等。
  • AIO异步非阻塞模式:这种模式下,我们不用一直坐在洗衣机面前等也不用每隔几分钟去看一下,而是洗衣机洗好后会发出铃声通知我洗好了。同步VS异步:洗衣机是不是在洗好后主动通知人。

5.2 技术使用

BIO方式:适用于连接数比较小的架构,这种方式对服务器资源要求比较高并且并发支持比较局限,是 JDK1.4 以前的唯一选择,但好处是程序代码直观简单易理解。

NIO方式:适用于连接数多且连接比较短的架构,比如 IM 即时通讯,但是编程比较复杂,JDK1.4 开始支持。

AIO方式:适用于连接数多且连接比较长的架构,比如文件服务器,调用操作系统参与并发操作让编程更加复杂,JDK7 开始支持。

5.3 代码实现

5.3.1 使用BIO实现文件的读写

//1.初始化对象
User user = new User();
user.setName("gwx");
user.setAge(18);

//2.将对象写入文件
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("userObjectFile"));
    oos.writeObject(user);
} catch (Exception e) {
    // 打印日志
} finally {
    // 关闭资源
}

//3.从文件读取对象
File file = new File("userObjectFile");
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(file));
    User newUser = (User) ois.readObject();
} catch (Exception e) {
    // 打印日志
} finally {
    // 关闭资源
}

5.3.2 使用NIO实现文件的读写

// 1.读文件
    static void readNIO() {
        String pathname = "/Users/gwx/input.txt";
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(new File(pathname));
            FileChannel channel = fin.getChannel();
            int capacity = 100;
            ByteBuffer bf = ByteBuffer.allocate(capacity);
            int length = -1;

            while ((length = channel.read(bf)) != -1) {
                bf.clear();
                byte[] bytes = bf.array();
                System.out.write(bytes, 0, length);
            }

            channel.close();

        } catch (FileNotFoundException e) {
            // 打印日志
        } catch (IOException e) {
            // 打印日志
        } finally {
            if (fin != null) {
                try {
                    fin.close();
                } catch (IOException e) {
                    // 打印日志
                }
            }
        }
    }

    //2.写文件
    static void writeNIO() {
        String filename = "out.txt";
        FileOutputStream fos = null;
        try {

            fos = new FileOutputStream(new File(filename));
            FileChannel channel = fos.getChannel();
            ByteBuffer src = Charset.forName("utf8").encode("会飞的架狗师");
            int length = 0;

            while ((length = channel.write(src)) != 0) {
                System.out.println("当前写入长度为:" + length);
            }

        } catch (FileNotFoundException e) {
            // 打印日志
        } catch (IOException e) {
            // 打印日志
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    // 打印日志
                }
            }
        }
    }

5.3.3 使用AIO实现文件的读写

/**
 * 1.读文件
 */
public class ReadFromFile {
    public static void main(String[] args) throws Exception {
        Path file = Paths.get("/Users/gwx/input.txt");
        AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
        // 100_000==100000,加下划线是为了易读
        ByteBuffer buffer = ByteBuffer.allocate(100_000);
        Future<Integer> result = channel.read(buffer, 0);

        while (!result.isDone()) {
            //打印日志
        }
        Integer bytesRead = result.get();
    }
}


/**
 * 2.写文件
 */
public class WriteToFile {

    public static void main(String[] args) throws Exception {
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
                Paths.get("/output.txt"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() {

            @Override
            public void completed(Integer result, Object attachment) {
                System.out.println("Attachment: " + attachment + " " + result
                        + " bytes written");
                System.out.println("CompletionHandler Thread ID: "
                        + Thread.currentThread().getId());
            }

            @Override
            public void failed(Throwable e, Object attachment) {
                System.err.println("Attachment: " + attachment + " failed with:");
                e.printStackTrace();
            }
        };

        System.out.println("主线程id为: " + Thread.currentThread().getId());
        fileChannel.write(ByteBuffer.wrap("第一次写".getBytes()), 0, "第一次写...",
                handler);
        fileChannel.write(ByteBuffer.wrap("第二次写".getBytes()), 0, "第二次写...",
                handler);

    }
}

你可能感兴趣的:(jvm,java,linux)