周末午后,在家里面进行电话面试,我问了面试者几个关于IO的问题,其中包括什么是BIO、NIO和AIO?三者有什么区别?具体如何使用等问题,可是面试者回答的并非很满意。因而我在面试评价中写道:"对Java的IO提醒理解不够深刻"。刚好被女友看到了。面试
IO,常写做I/O,是Input/Output的简称,即输入/输出。一般指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其余周边设备之间的输入和输出。编程
输入/输出是信息处理系统(例如计算机)与外部世界(多是人类或另外一信息处理系统)之间的通讯。bash
输入是系统接收的信号或数据,输出则是从其发送的信号或数据。服务器
在Java中,提供了一些列API,能够供开发者来读写外部数据或文件。咱们称这些API为Java IO。网络
IO是Java中比较重要,且比较难的知识点,主要是由于随着Java的发展,目前有三种IO共存。分别是BIO、NIO和AIO。架构
BIO 全称Block-IO 是一种同步且阻塞的通讯模式。是一个比较传统的通讯方式,模式简单,使用方便。但并发处理能力低,通讯耗时,依赖网速。并发
Java NIO,全程 Non-Block IO ,是Java SE 1.4版之后,针对网络传输效能优化的新功能。是一种非阻塞同步的通讯模式。异步
NIO 与原来的 I/O 有一样的做用和目的, 他们之间最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。async
面向流的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。ide
面向块的 I/O 系统以块的形式处理数据。每个操做都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。可是面向块的 I/O 缺乏一些面向流的 I/O 所具备的优雅性和简单性。
Java AIO,全程 Asynchronous IO,是异步非阻塞的IO。是一种非阻塞异步的通讯模式。
在NIO的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
首先,咱们站在宏观的角度,从新画一下重点:
BIO (Blocking I/O):同步阻塞I/O模式。
NIO (New I/O):同步非阻塞模式。
AIO (Asynchronous I/O):异步非阻塞I/O模型。
那么,同步阻塞、同步非阻塞、异步非阻塞都是怎么回事呢?关于这部份内容也能够查看《漫话:如何给女友解释什么是IO中的阻塞、非阻塞、同步、异步?》。
同步阻塞模式:这种模式下,咱们的工做模式是先来到厨房,开始烧水,并坐在水壶面前一直等着水烧开。
同步非阻塞模式:这种模式下,咱们的工做模式是先来到厨房,开始烧水,可是咱们不一直坐在水壶前面等,而是回到客厅看电视,而后每隔几分钟到厨房看一下水有没有烧开。
异步非阻塞I/O模型:这种模式下,咱们的工做模式是先来到厨房,开始烧水,咱们不一一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开以后他会通知我。
阻塞VS非阻塞:人是否坐在水壶前面一直等。
同步VS异步:水壶是否是在水烧开以后主动通知人。
BIO方式适用于链接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4之前的惟一选择,但程序直观简单易理解。
NIO方式适用于链接数目多且链接比较短(轻操做)的架构,好比聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式适用于链接数目多且链接比较长(重操做)的架构,好比相册服务器,充分调用OS参与并发操做,编程比较复杂,JDK7开始支持。
使用BIO实现文件的读取和写入。
//Initializes The Object
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);
//Write Obj to File
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(oos);
}
//Read Obj from File
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
User1 newUser = (User1) ois.readObject();
System.out.println(newUser);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(ois);
try {
FileUtils.forceDelete(file);
} catch (IOException e) {
e.printStackTrace();
}
}
//Initializes The Object
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);
//Write Obj to File
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(oos);
}
//Read Obj from File
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(file));
User1 newUser = (User1) ois.readObject();
System.out.println(newUser);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(ois);
try {
FileUtils.forceDelete(file);
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码
使用NIO实现文件的读取和写入。
static void readNIO() {
String pathname = "C:\\Users\\adew\\Desktop\\jd-gui.cfg";
FileInputStream fin = null;
try {
fin = new FileInputStream(new File(pathname));
FileChannel channel = fin.getChannel();
int capacity = 100;// 字节
ByteBuffer bf = ByteBuffer.allocate(capacity);
int length = -1;
while ((length = channel.read(bf)) != -1) {
bf.clear();
byte[] bytes = bf.array();
System.out.write(bytes, 0, length);
System.out.println();
}
channel.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
static void writeNIO() {
String filename = "out.txt";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(filename));
FileChannel channel = fos.getChannel();
ByteBuffer src = Charset.forName("utf8").encode("你好你好你好你好你好");
int length = 0;
while ((length = channel.write(src)) != 0) {
System.out.println("写入长度:" + length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
复制代码
使用AIO实现文件的读取和写入
public class ReadFromFile {
public static void main(String[] args) throws Exception {
Path file = Paths.get("/usr/a.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
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() {
}
}
public class WriteToFile {
public static void main(String[] args) throws Exception {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
Paths.get("/asynchronous.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);
}
}
复制代码
滴滴滴,水开了。