BIO,NIO,AIO详解

时间:2020-07-01 10:15:36   收藏:0   阅读:76

Java中的IO,BIO,NIO,AIO详解

IO

BIO,NIO和AIO的关系

  1. BIO:java.io包.基于流模型实现,使用同步,阻塞方式.即:读输入流或写输出流时,在读或写动作完成之前,读(写)线程一直阻塞.性能差.
  2. NIO:java.nio包.可以构建多路复用,同步非阻塞的IO操作.
  3. AIO:Java 1.7之后引入的包.提供异步非阻塞的IO操作.基于事件和回调机制实现的.程序操作后直接返回,不阻塞,后台完成处理后,由系统通知相应的线程进行后续的操作.

IO的分类

IO的使用

InputStream的使用

InputStream inputStream = new FileInputStream("src\\IOBIONIOAIO.md");
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
String str = new String(bytes);
inputStream.close();
System.out.println(str);

OutputStream的使用

OutputStream outputStream = null;
outputStream = new FileOutputStream("src\\IOBIONIOAIO.md",true);
outputStream.write("\nOutputStream测试".getBytes("utf-8"));
outputStream.close();

Writer的使用

Writer writer = new FileWriter("src\\IOBIONIOAIO.md",true);
writer.append("\n使用Writer向文件写入数据");
writer.close();

Reader的使用

Reader reader = new FileReader("src\\IOBIONIOAIO.md");
BufferedReader br = new BufferedReader(reader);
StringBuffer sb = new StringBuffer();
String str = null;
while ((str = br.readLine()) != null){
    sb.append(str+"\n");
}
br.close();
reader.close();
System.out.println(sb.toString());

同步,异步,阻塞,非阻塞

同步与异步

同步

异步

阻塞和非阻塞

阻塞

调用结果返回之前,当前线程会被挂起.调用线程只有在得到结果之后才返回.

非阻塞

在没有得到结果之前,不会阻塞当前线程.
线程可以在结果返回之前完成其他任务,提高了CPU的利用率.

问题:系统的线程切换增加,需要权衡增加的CPU使用时间和线程切换的成本.

同/异,阻/非阻塞的组合

组合方式 性能
同步阻塞 I/O性能差,CPU大部分在空闲状态
同步非阻塞 提升I/O性能,增加CPU消耗
异步阻塞 对I/O能够提升效率
异步非阻塞 集群之间的消息同步机制

文件读写

// 使用FileWriter向文件写入数据
public void fileWriterTest() throws IOException {
    FileWriter fw = new FileWriter("src\\IOBIONIOAIO.md",true);
    fw.write("\n来自FileWriter写入的内容");
    fw.close();
}

// 使用FileReader读取文件的内容
public void fileReaderTest() throws IOException {
    FileReader fr = new FileReader("src\\IOBIONIOAIO.md");
    BufferedReader br = new BufferedReader(fr);
    StringBuffer sb = new StringBuffer();
    String str;
    while ((str = br.readLine())!=null){
        sb.append(str+"\n");
    }
    br.close();
    fr.close();
    System.out.println(sb.toString());
}

使用java.nio包中的Files实现对文件的读写:

public void filesWrite() throws IOException {
    Files.write(Paths.get("src\\IOBIONIOAIO.md"),"\n使用Files向文件写入数据".getBytes(), StandardOpenOption.APPEND);
}

public void filesRead() throws IOException {
    byte[] bytes = Files.readAllBytes(Paths.get("src\\IOBIONIOAIO.md"));
    System.out.println(new String(bytes).toString());
}

Socket和NIO的多路复用

传统的Socket实现

服务器只给客户端发消息.
客户端将接收到的消息打印.

/**
* 服务器端:
* 调用accept()阻塞线程等待客户端连接.
* 客户端连接后将数据传输过去
*/
public void servers(){
    Thread thread = new Thread(() -> {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                Socket socket = serverSocket.accept();
                try (PrintWriter printWriter = new PrintWriter(socket.getOutputStream())) {
                    printWriter.println("来自于服务器端的消息");
                    printWriter.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    });
    thread.start();
}

/**
* 客户端:
* 打开指定的socket端口,
* 使用BufferedReader读取端口传来的数据
*/
public void client(){
    try (Socket socket = new Socket(InetAddress.getLocalHost(),port)){
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        br.lines().forEach(s-> System.out.println(s));
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

示意图:

技术分享图片

NIO多路复用

public void servers(){
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4, 60l, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    threadPool.execute(()->{
        try (Selector selector =  Selector.open();
                ServerSocketChannel serverSocketChannel =  ServerSocketChannel.open()){
            serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(),port));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true){
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    SelectionKey key = iterator.next();
                    try(SocketChannel channel = ((ServerSocketChannel)key.channel()).accept()){
                        channel.write(Charset.defaultCharset().encode("来自服务器通过NIO写入数据"));
                    }
                    iterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    });
}

public void client(){
    try (Socket cSocket =  new Socket(InetAddress.getLocalHost(),port)){
        BufferedReader br = new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
        br.lines().forEach(s-> System.out.println(s));
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

流程:

示意图:
技术分享图片

参考:

原文:https://www.cnblogs.com/truestoriesavici01/p/13217272.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!