漫话:如何给女朋友解释什么是BIO、NIO和AIO?
本文經(jīng)授權(quán)轉(zhuǎn)載自微信公眾號(hào):漫話編程
周末午后,在家里面進(jìn)行電話面試,我問(wèn)了面試者幾個(gè)關(guān)于IO的問(wèn)題,其中包括什么是BIO、NIO和AIO?三者有什么區(qū)別?具體如何使用等問(wèn)題,但是面試者回答的并不是很滿意。于是我在面試評(píng)價(jià)中寫(xiě)道:"對(duì)Java的IO提醒理解不夠深入"。恰好被女朋友看到了。
Java IOIO,常協(xié)作I/O,是Input/Output的簡(jiǎn)稱(chēng),即輸入/輸出。通常指數(shù)據(jù)在內(nèi)部存儲(chǔ)器(內(nèi)存)和外部存儲(chǔ)器(硬盤(pán)、優(yōu)盤(pán)等)或其他周邊設(shè)備之間的輸入和輸出。
輸入/輸出是信息處理系統(tǒng)(例如計(jì)算機(jī))與外部世界(可能是人類(lèi)或另一信息處理系統(tǒng))之間的通信。
輸入是系統(tǒng)接收的信號(hào)或數(shù)據(jù),輸出則是從其發(fā)送的信號(hào)或數(shù)據(jù)。
在Java中,提供了一些列API,可以供開(kāi)發(fā)者來(lái)讀寫(xiě)外部數(shù)據(jù)或文件。我們稱(chēng)這些API為Java IO。
IO是Java中比較重要,且比較難的知識(shí)點(diǎn),主要是因?yàn)殡S著Java的發(fā)展,目前有三種IO共存。分別是BIO、NIO和AIO。
Java BIOBIO 全稱(chēng)Block-IO 是一種同步且阻塞的通信模式。是一個(gè)比較傳統(tǒng)的通信方式,模式簡(jiǎn)單,使用方便。但并發(fā)處理能力低,通信耗時(shí),依賴網(wǎng)速。
Java NIOJava NIO,全程 Non-Block IO ,是Java SE 1.4版以后,針對(duì)網(wǎng)絡(luò)傳輸效能優(yōu)化的新功能。是一種非阻塞同步的通信模式。
NIO 與原來(lái)的 I/O 有同樣的作用和目的, 他們之間最重要的區(qū)別是數(shù)據(jù)打包和傳輸?shù)姆绞健T瓉?lái)的 I/O 以流的方式處理數(shù)據(jù),而 NIO 以塊的方式處理數(shù)據(jù)。
面向流的 I/O 系統(tǒng)一次一個(gè)字節(jié)地處理數(shù)據(jù)。一個(gè)輸入流產(chǎn)生一個(gè)字節(jié)的數(shù)據(jù),一個(gè)輸出流消費(fèi)一個(gè)字節(jié)的數(shù)據(jù)。
面向塊的 I/O 系統(tǒng)以塊的形式處理數(shù)據(jù)。每一個(gè)操作都在一步中產(chǎn)生或者消費(fèi)一個(gè)數(shù)據(jù)塊。按塊處理數(shù)據(jù)比按(流式的)字節(jié)處理數(shù)據(jù)要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優(yōu)雅性和簡(jiǎn)單性。
Java AIOJava AIO,全程 Asynchronous IO,是異步非阻塞的IO。是一種非阻塞異步的通信模式。
在NIO的基礎(chǔ)上引入了新的異步通道的概念,并提供了異步文件通道和異步套接字通道的實(shí)現(xiàn)。
三種IO的區(qū)別首先,我們站在宏觀的角度,重新畫(huà)一下重點(diǎn):
BIO (Blocking I/O):同步阻塞I/O模式。
NIO (New I/O):同步非阻塞模式。
AIO (Asynchronous I/O):異步非阻塞I/O模型。
那么,同步阻塞、同步非阻塞、異步非阻塞都是怎么回事呢?關(guān)于這部分內(nèi)容也可以查看《漫話:如何給女朋友解釋什么是IO中的阻塞、非阻塞、同步、異步?》。
同步阻塞模式:這種模式下,我們的工作模式是先來(lái)到廚房,開(kāi)始燒水,并坐在水壺面前一直等著水燒開(kāi)。
同步非阻塞模式:這種模式下,我們的工作模式是先來(lái)到廚房,開(kāi)始燒水,但是我們不一直坐在水壺前面等,而是回到客廳看電視,然后每隔幾分鐘到廚房看一下水有沒(méi)有燒開(kāi)。
異步非阻塞I/O模型:這種模式下,我們的工作模式是先來(lái)到廚房,開(kāi)始燒水,我們不一一直坐在水壺前面等,也不隔一段時(shí)間去看一下,而是在客廳看電視,水壺上面有個(gè)開(kāi)關(guān),水燒開(kāi)之后他會(huì)通知我。
阻塞VS非阻塞:人是否坐在水壺前面一直等。
同步VS異步:水壺是不是在水燒開(kāi)之后主動(dòng)通知人。
適用場(chǎng)景BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對(duì)服務(wù)器資源要求比較高,并發(fā)局限于應(yīng)用中,JDK1.4以前的唯一選擇,但程序直觀簡(jiǎn)單易理解。
NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中,編程比較復(fù)雜,JDK1.4開(kāi)始支持。
AIO方式適用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu),比如相冊(cè)服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開(kāi)始支持。
使用方式使用BIO實(shí)現(xiàn)文件的讀取和寫(xiě)入。
//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實(shí)現(xiàn)文件的讀取和寫(xiě)入。
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;//?字節(jié)????????????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("寫(xiě)入長(zhǎng)度:"?+?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;//?字節(jié)
????????????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("寫(xiě)入長(zhǎng)度:"?+?length);
????????????}
????????}?catch?(FileNotFoundException?e)?{
????????????e.printStackTrace();
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}?finally?{
????????????if?(fos?!=?null)?{
????????????????try?{
????????????????????fos.close();
????????????????}?catch?(IOException?e)?{
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}
????}
使用AIO實(shí)現(xiàn)文件的讀取和寫(xiě)入
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);
??}
}
滴滴滴,水開(kāi)了。
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的漫话:如何给女朋友解释什么是BIO、NIO和AIO?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为啥HashMap的默认容量是16?
- 下一篇: AI工程师的崩溃,是从你的薪资比我高开始