在Java中,BIO(Blocking I/O)是一种传统的、同步的输入输出(I/O)模型。它意味着每次进行I/O操作时,线程会被阻塞,直到数据完全读取或写入完毕。BIO通常是阻塞式的,当程序发出读取或写入请求时,它会等待I/O操作完成才会继续执行后续代码。

BIO的特点:

  1. 同步阻塞:每次 I/O 操作都会阻塞当前线程,直到操作完成。
  2. 简单:BIO 是 Java 中最简单的一种 I/O 方式,易于理解和使用。
  3. 效率较低:由于阻塞模式,BIO 适用于并发量较低的场景,但当需要处理大量并发连接时效率较差。

常见的 BIO 操作:

  1. 文件 I/O(FileInputStream , FileOutputStream , FileReader , FileWriter)
  2. 网络 I/O(Socket , ServerSocket)

BIO 在网络编程中的应用

BIO 模式通常用于经典的 Socket 和 ServerSocket,当进行网络通信时,客户端和服务器的每次 I/O 操作都会阻塞,直到读取或写入完成。

BIO 网络示例:

import java.io.*;
import java.net.*;

public class BioServer {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(12345)) {
            System.out.println("Server is waiting for client connection...");
            try (Socket socket = serverSocket.accept()) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println("Received from client: " + message);
                    writer.println("Server response: " + message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端:

import java.io.*;
import java.net.*;

public class BioClient {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 12345)) {
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            writer.println("Hello Server!");
            String response = reader.readLine();
            System.out.println("Server says: " + response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedWriter 和 PrintWriter 的主要区别

特性 BufferedWriter PrintWriter
写入方法 只有 write(),只能写字符或字符数组,需要手动处理换行 提供 print() / println() / printf() 方法,可以直接写字符串并自动处理换行
自动刷新 不会自动刷新缓冲区,需要手动调用 flush() 可以在构造函数里设置 autoFlush = true,在调用 println() 时自动刷新
方便性 适合写大块文本、性能优化(减少系统调用次数) 适合交互式通信,写一行就立即发给客户端,非常方便
用途 文件写入、日志写入 网络通信、控制台输出

为什么这个例子用PrintWriter

在我的 BIO 服务器中:

PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
  • 自动刷新:第二个参数 true 表示每次调用 println() 时都会自动刷新缓冲区,把消息立即发给客户端。
  • 方便写行:我们想“一行一行地回传客户端消息”,println() 就可以直接实现。
  • 无需手动flush():如果用 BufferedWriter,必须每次写完后调用 flush() 才能让客户端收到数据,否则客户端可能一直阻塞等不到消息。
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Server response: " + message + "\n");
writer.flush(); // 必须手动刷新,否则客户端收不到

可以工作,但麻烦了一点,而且 PrintWriter 已经封装好了“写一行就发”的功能,非常适合网络通信场景。

总结:

  • BIO 是 Java 中最基础的 I/O 操作方式,适用于简单的文件和网络 I/O 操作。
  • 在高并发场景下,BIO 的效率较低,因为每个连接都会占用一个线程,容易导致资源浪费和性能瓶颈。
  • 如果需要处理大量并发连接,可以考虑 NIO(New I/O)或 AIO(Asynchronous I/O)作为替代方案。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐