IO(1)- BIO

101 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

重要概念

  • 阻塞IO非阻塞IO
    这两个概念指的是在请求操作系统IO后,如果IO资源没有准备好,后续怎么操作,前者等待,后者继续执行(会不断地轮询,直到有IO资源准备好)。是程序级别的。

  • 同步IO异步IO
    同步IO 请求后,请求一阻塞或者轮询的方式等待IO完成,需要将内核态准备就绪的数据拷贝到用户态,需要阻塞用户态并等待IO完成
    异步IO 请求后立即返回继续执行后续逻辑流,不需要阻塞

IO的分类

IO可以分为三类 BIO、NIO、AIO
BIO:同步阻塞IO,使用BIO读取数据时,线程会阻塞住,并且需要线程主动去查询是否有数据可读,并且需要处理完一个socket之后才能处理下一个socket

AIO:异步非阻塞IO,使用AIO读取数据时,现成不会阻塞,并且当有数据可读时会通知线程,不需要线程主动去查询

NIO:同步非阻塞IO,使用NIO时,线程不会阻塞,但需要线程主动的去查询是否有IO事件

BIO

BIO的工作机制

image.png

BIO的特性 每个客户端对应一个线程,即多少个客户端多少个线程

BIO的实现

server端

package com.example.io.bio;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class BIOServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8000);

        // (1) 接收新连接线程
        new Thread(() -> {
            while (true) {
                try {
                    // (1) 阻塞方法获取新的连接
                    Socket socket = serverSocket.accept();

                    // (2) 每一个新的连接都创建一个线程,负责读取数据
                    new Thread(() -> {
                        try {
                            int len;
                            byte[] data = new byte[1024];
                            InputStream inputStream = socket.getInputStream();
                            // (3) 按字节流方式读取数据
                            while ((len = inputStream.read(data)) != -1) {
                                System.out.println(new String(data, 0, len));
                            }
                        } catch (IOException e) {
                        }
                    }).start();

                } catch (IOException e) {
                }

            }
        }).start();
    }
}

client端

package com.example.io.bio;

import java.io.IOException;
import java.net.Socket;
import java.util.Date;

public class BIOClient {
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                Socket socket = new Socket("127.0.0.1", 8000);
                while (true) {
                    try {
                        socket.getOutputStream().write((new Date() + ": hello world").getBytes());
                        Thread.sleep(2000);
                    } catch (Exception e) {
                    }
                }
            } catch (IOException e) {
            }
        }).start();
    }
}

BIO的问题

  1. 线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起
  2. 线程切换效率低下:单机 CPU 核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。