漫话:如何给女朋友解释什么是BIO、NIO和AIO?
本文經授權轉載自微信公眾號:漫話編程
周末午后,在家里面進行電話面試,我問了面試者幾個關于IO的問題,其中包括什么是BIO、NIO和AIO?三者有什么區別?具體如何使用等問題,但是面試者回答的并不是很滿意。于是我在面試評價中寫道:"對Java的IO提醒理解不夠深入"。恰好被女朋友看到了。
Java IOIO,常協作I/O,是Input/Output的簡稱,即輸入/輸出。通常指數據在內部存儲器(內存)和外部存儲器(硬盤、優盤等)或其他周邊設備之間的輸入和輸出。
輸入/輸出是信息處理系統(例如計算機)與外部世界(可能是人類或另一信息處理系統)之間的通信。
輸入是系統接收的信號或數據,輸出則是從其發送的信號或數據。
在Java中,提供了一些列API,可以供開發者來讀寫外部數據或文件。我們稱這些API為Java IO。
IO是Java中比較重要,且比較難的知識點,主要是因為隨著Java的發展,目前有三種IO共存。分別是BIO、NIO和AIO。
Java BIOBIO 全稱Block-IO 是一種同步且阻塞的通信模式。是一個比較傳統的通信方式,模式簡單,使用方便。但并發處理能力低,通信耗時,依賴網速。
Java NIOJava NIO,全程 Non-Block IO ,是Java SE 1.4版以后,針對網絡傳輸效能優化的新功能。是一種非阻塞同步的通信模式。
NIO 與原來的 I/O 有同樣的作用和目的, 他們之間最重要的區別是數據打包和傳輸的方式。原來的 I/O 以流的方式處理數據,而 NIO 以塊的方式處理數據。
面向流的 I/O 系統一次一個字節地處理數據。一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據。
面向塊的 I/O 系統以塊的形式處理數據。每一個操作都在一步中產生或者消費一個數據塊。按塊處理數據比按(流式的)字節處理數據要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。
Java AIOJava AIO,全程 Asynchronous IO,是異步非阻塞的IO。是一種非阻塞異步的通信模式。
在NIO的基礎上引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實現。
三種IO的區別首先,我們站在宏觀的角度,重新畫一下重點:
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?ObjectUser1?user?=?new?User1();user.setName("hollis");user.setAge(23);System.out.println(user);//Write?Obj?to?FileObjectOutputStream?oos?=?null;try?{????oos?=?new?ObjectOutputStream(new?FileOutputStream("tempFile"));????oos.writeObject(user);}?catch?(IOException?e)?{????e.printStackTrace();}?finally?{????IOUtils.closeQuietly(oos);}//Read?Obj?from?FileFile?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?ObjectUser1?user?=?new?User1();user.setName("hollis");user.setAge(23);System.out.println(user);//Write?Obj?to?FileObjectOutputStream?oos?=?null;try?{????oos?=?new?ObjectOutputStream(new?FileOutputStream("tempFile"));????oos.writeObject(user);}?catch?(IOException?e)?{????e.printStackTrace();}?finally?{????IOUtils.closeQuietly(oos);}//Read?Obj?from?FileFile?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();????}}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();????????????????}????????????}????????}????}????????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);??}}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);
??}
}
滴滴滴,水開了。
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的漫话:如何给女朋友解释什么是BIO、NIO和AIO?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为啥HashMap的默认容量是16?
- 下一篇: Servlet服务器搭建过程中一些经验