Java中的BIO、NIO和AIO分别代表着阻塞式I/O、非阻塞式I/O和异步I/O。它们之间的主要区别在于处理I/O操作的方式。
BIO采用阻塞式的方式,即当一个线程执行一个I/O操作时,该线程会被阻塞,直到I/O操作完成。这意味着在进行网络通信时,每个连接都需要一个独立的线程,会导致资源消耗较大。
以下是一个简单的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) {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
while (true) {
// 阻塞等待客户端连接
Socket socket = serverSocket.accept();
// 每个连接创建一个线程处理
new Thread(() -> {
try (InputStream inputStream = socket.getInputStream()) {
byte[] buffer = new byte[1024];
int length;
// 阻塞读取数据
while ((length = inputStream.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, length));
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO使用了非阻塞式的方式,通过Selector
选择器实现。一个线程可以处理多个连接,当一个连接的I/O操作不可用时,线程可以切换到处理其他连接。
以下是一个简单的NIO服务器的示例:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class NioServer {
public static void main(String[] args) {
try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open()) {
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = socketChannel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
System.out.println(new String(buffer.array(), 0, bytesRead));
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
AIO使用异步方式处理I/O操作,通过回调函数通知应用程序。AIO对于处理大量连接时表现更好,因为不需要为每个连接分配一个线程。
以下是一个简单的AIO服务器的示例:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class AioServer {
public static void main(String[] args) {
try (AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open()) {
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
serverSocketChannel.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer bytesRead, ByteBuffer buffer) {
buffer.flip();
System.out.println(new String(buffer.array(), 0, bytesRead));
}
@Override
public void failed(Throwable exc, ByteBuffer buffer) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
// 阻塞主线程,保
持服务端运行
Thread.sleep(Long.MAX_VALUE);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
这个示例中,当有连接建立时,通过CompletionHandler
处理读取数据的异步操作。