终于搞懂 BIO,NIO,AIO 了
Posted 沸羊羊_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了终于搞懂 BIO,NIO,AIO 了相关的知识,希望对你有一定的参考价值。
前言
I/O,通常指数据在内部存储器(内存)和外部存储器(磁盘)之间的输入和输出。
在 Java
中提供了一些 API,可以供开发者来读写外部数据或文件,称这些 API 为 Java IO
, 随着 Java
的发展,目前有三种IO:BIO
,NIO
,AIO
,下面对这三种 IO 进行介绍。
在讲述BIO
,NIO
,AIO
前,先来弄清楚四个概念:同步异步,阻塞非阻塞。
同步/异步
同步/异步
关注的是消息通信机制。
同步(Synchronous)
是指发起一个调用后,调用方必须等待此调用返回结果后才能继续执行。异步(Asynchronous)
是指发起一个调用后,调用方可继续执行后续操作,被调用者执行结束主动给调用方返回结果。
比如,同步就是主线程开始执行,调用其中一个sum()方法,主线程要等待sum()方法执行结束并返回结果再执行后续程序代码;而异步是主线程执行调用 sum()方法,有另一个线程去执行 sum() 方法内部逻辑,而主线程在调用完 sum() 后可执行后续程序代码,无需等到sum()结果返回才执行。
阻塞/非阻塞
阻塞/非阻塞
关注的是程序在等待调用结果时的状态,区别在于第一步发起 IO 请求后是否会被阻塞。
阻塞
是指调用结果返回前,当前线程会被挂起,调用线程只有在得到结果之后才返回。非阻塞
是指在调用结果返回前,不影响当前线程执行其他操作,也就是不会阻塞当前线程。
同步/异步
经常会和阻塞/非阻塞
混为一谈。
同步/异步
指的是消息的通信机制,同步是指当前线程要拿到执行结果后再返回,异步是指当前线程无需等待执行结果,可以执行当前线程的后续操作,同步与异步的区别是如何获取执行结果的事情。阻塞/非阻塞
指的是程序在调用后线程的状态,是基于同一个线程来说的,阻塞是指调用后线程被置为阻塞(Blocked) 的状态,非阻塞是指调用后线程仍然处于 运行(Running)的状态,阻塞与非阻塞的区别是当前线程是否处于阻塞的状态。所以,二者指的不是一个维度的概念。
BIO、NIO、AIO
我们用非常经典的烧水例子来说明这三个概念的区别。
BIO(Block IO)
是一种同步阻塞的通信模式,是一个比较传统的通信方式,模式简单、使用方便,但并发处理能力低,通信耗时,依赖网速。
NIO(Non-Bock) IO
是一种同步非阻塞的通信模式,针对网络传输效能优化的新功能。
AIO(Asynchronous IO)
是一种异步非阻塞的通信模式。
同步阻塞的工作模式是先来到厨房,开始烧水,并在水壶旁等待直到水开了为止。
同步非阻塞的工作模式是指来到厨房,开始烧水,这次不在水壶旁等着,回到客厅看电视,每隔几分钟去检查水是否烧开了。
异步非阻塞的工作模式是指来到厨房,开始烧水,回到客厅看电视,直到听到水烧开后水壶的提示音。
同步vs异步:指的是被调用方以何种方式返回调用结果?(我们如何知道水壶中的水烧开了,是主动发现还是水壶被动提醒)
阻塞vs非阻塞:指的是调用方在调用后的状态是否是阻塞?(我们把水壶烧水开关打开后,我们是否在水壶旁等待水烧开)
适用场景
BIO
适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO
适用于连接数目比较多且连接比较短的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO
方式适用于连接数目多且连接比较长的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
实战
下面将从代码的角度出发,看看这三种架构模式的区别。
BIO
在 JDK1.4以前,用 Java 编写网络请求,都是建立一个 ServerSocket
,客户端建立 socket
时会询问是否有线程可以处理,如果没有,要么等待,要么被拒绝。
写文件
public class WriteFileTest {
public static void main(String[] args) throws IOException {
User user = new User();
user.setAge(10);
user.setName("feiyangyang");
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("bioFile"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
oos.close();
}
}
}
读文件
public class ReadFileTest {
public static void main(String[] args) throws IOException {
File bioFile = new File("bioFile");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(bioFile));
User user = (User) ois.readObject();
System.out.println(user);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
ois.close();
}
}
}
NIO
在Java中,在JDK1.4以后提供了一套API专门操作非阻塞I/O,我们可以在 java.nio 包及其子包中找到相关类和接口。
这套 API 由三个主要部分组成:
- 缓冲区 (Buffers)
- 通道 (Channels)
- 非阻塞 I/O 的核心类组成
写文件
public class WriteFileTest {
public static void main(String[] args) {
String fileName = "nioFile";
try (FileOutputStream fos = new FileOutputStream(new File(fileName))) {
FileChannel channel = fos.getChannel();
ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode("你好你好..");
int length = 0;
while ((length = channel.write(byteBuffer)) != 0) {
System.out.println("写入长度:" + length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
读文件
public class ReadFileTest {
public static void main(String[] args) throws IOException {
String fileName = "C:\\IODemo\\nioFile";
try (FileInputStream fis = new FileInputStream(new File(fileName)); FileChannel channel = fis.getChannel()) {
int capacity = 100;
ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
int length = -1;
while ((length = channel.read(byteBuffer)) != -1) {
byteBuffer.clear();
byte[] array = byteBuffer.array();
System.out.write(array, 0, length);
System.out.println();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
AIO
使用 java.nio
包中的 AsynchronousFileChannel
类和 CompletionHandler
分别做 通道 和 处理器。
写文件
public class WriteFileTest {
public static void main(String[] args) throws IOException {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
Paths.get("aioFile.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("Main Thread ID: " + Thread.currentThread().getId());
fileChannel.write(ByteBuffer.wrap("Sample".getBytes()), 0, "First Write",
handler);
fileChannel.write(ByteBuffer.wrap("Box".getBytes()), 0, "Second Write",
handler);
}
}
读文件
public class ReadFileTest {
public static void main(String[] args) throws ExecutionException, InterruptedException, IOException {
Path file = Paths.get("aioFile.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
ByteBuffer buffer = ByteBuffer.allocate(10);
Future<Integer> result = channel.read(buffer, 0);
while (!result.isDone()) {
ProfitCalculator.calculateTax();
}
Integer bytesRead = result.get();
System.out.println("Bytes read [" + bytesRead + "]");
}
}
class ProfitCalculator {
public ProfitCalculator() {
}
public static void calculateTax() {
}
}
小结
本文主要介绍了 同步/异步
,阻塞/非阻塞
,BIO
,NIO
,AIO
的基本概念和理解,如对其他内容感兴趣,可继续关注小编其他文章。
以上是关于终于搞懂 BIO,NIO,AIO 了的主要内容,如果未能解决你的问题,请参考以下文章