Java中BIO、NIO和AIO的區(qū)別、原理與用法
IO
什么是IO? 它是指計(jì)算機(jī)與外部世界或者一個(gè)程序與計(jì)算機(jī)的其余部分的之間的接口。它對(duì)于任何計(jì)算機(jī)系統(tǒng)都非常關(guān)鍵,因而所有 I/O 的主體實(shí)際上是內(nèi)置在操作系統(tǒng)中的。單獨(dú)的程序一般是讓系統(tǒng)為它們完成大部分的工作。
在 Java 編程中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被視為單個(gè)的字節(jié)的移動(dòng),通過(guò)一個(gè)稱為 Stream 的對(duì)象一次移動(dòng)一個(gè)字節(jié)。流 I/O 用于與外部世界接觸。它也在內(nèi)部使用,用于將對(duì)象轉(zhuǎn)換為字節(jié),然后再轉(zhuǎn)換回對(duì)象。
BIO
Java BIO即Block I/O , 同步并阻塞的IO。
BIO就是傳統(tǒng)的java.io包下面的代碼實(shí)現(xiàn)。
NIO
什么是NIO? NIO 與原來(lái)的 I/O 有同樣的作用和目的, 他們之間最重要的區(qū)別是數(shù)據(jù)打包和傳輸?shù)姆绞?。原?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ù)。為流式數(shù)據(jù)創(chuàng)建過(guò)濾器非常容易。鏈接幾個(gè)過(guò)濾器,以便每個(gè)過(guò)濾器只負(fù)責(zé)單個(gè)復(fù)雜處理機(jī)制的一部分,這樣也是相對(duì)簡(jiǎn)單的。不利的一面是,面向流的 I/O 通常相當(dāng)慢。
一個(gè) 面向塊 的 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)單性。
AIO
Java AIO即Async非阻塞,是異步非阻塞的IO。
區(qū)別及聯(lián)系
- BIO (Blocking I/O):同步阻塞I/O模式,數(shù)據(jù)的讀取寫入必須阻塞在一個(gè)線程內(nèi)等待其完成。這里假設(shè)一個(gè)燒開水的場(chǎng)景,有一排水壺在燒開水,BIO的工作模式就是, 叫一個(gè)線程停留在一個(gè)水壺那,直到這個(gè)水壺?zé)_,才去處理下一個(gè)水壺。但是實(shí)際上線程在等待水壺?zé)_的時(shí)間段什么都沒有做。
- NIO (New I/O):同時(shí)支持阻塞與非阻塞模式,但這里我們以其同步非阻塞I/O模式來(lái)說(shuō)明,那么什么叫做同步非阻塞?如果還拿燒開水來(lái)說(shuō),NIO的做法是叫一個(gè)線程不斷的輪詢每個(gè)水壺的狀態(tài),看看是否有水壺的狀態(tài)發(fā)生了改變,從而進(jìn)行下一步的操作。
- AIO ( Asynchronous I/O):異步非阻塞I/O模型。異步非阻塞與同步非阻塞的區(qū)別在哪里?異步非阻塞無(wú)需一個(gè)線程去輪詢所有IO操作的狀態(tài)改變,在相應(yīng)的狀態(tài)改變后,系統(tǒng)會(huì)通知對(duì)應(yīng)的線程來(lái)處理。對(duì)應(yīng)到燒開水中就是,為每個(gè)水壺上面裝了一個(gè)開關(guān),水燒開之后,水壺會(huì)自動(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開始支持。
- AIO方式適用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu),比如相冊(cè)服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開始支持。
使用方式
使用BIO實(shí)現(xiàn)文件的讀取和寫入。
//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實(shí)現(xiàn)文件的讀取和寫入。
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);
System.out.println("限制是:" + bf.limit() + "容量是:" + bf.capacity()
+ "位置是:" + bf.position());
int length = -1;
while ((length = channel.read(bf)) != -1) {
/*
* 注意,讀取后,將位置置為0,將limit置為容量, 以備下次讀入到字節(jié)緩沖中,從0開始存儲(chǔ)
*/
bf.clear();
byte[] bytes = bf.array();
System.out.write(bytes, 0, length);
System.out.println();
System.out.println("限制是:" + bf.limit() + "容量是:" + bf.capacity()
+ "位置是:" + bf.position());
}
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("你好你好你好你好你好");
// 字節(jié)緩沖的容量和limit會(huì)隨著數(shù)據(jù)長(zhǎng)度變化,不是固定不變的
System.out.println("初始化容量和limit:" + src.capacity() + ","
+ src.limit());
int length = 0;
while ((length = channel.write(src)) != 0) {
/*
* 注意,這里不需要clear,將緩沖中的數(shù)據(jù)寫入到通道中后 第二次接著上一次的順序往下讀
*/
System.out.println("寫入長(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)文件的讀取和寫入
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);
}
}
到此這篇關(guān)于Java中BIO、NIO和AIO的區(qū)別、原理與用法的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 淺談Java中BIO、NIO和AIO的區(qū)別和應(yīng)用場(chǎng)景
- Java中網(wǎng)絡(luò)IO的實(shí)現(xiàn)方式(BIO、NIO、AIO)介紹
- 詳解Java 網(wǎng)絡(luò)IO編程總結(jié)(BIO、NIO、AIO均含完整實(shí)例代碼)
- Java中AIO、BIO、NIO應(yīng)用場(chǎng)景及區(qū)別
- Java中BIO、NIO、AIO的理解
- java的三種IO模型詳解(BIO、NIO、AIO)
- Java?IO模型之BIO、NIO、AIO三種常見IO模型解析
- java中BIO、NIO、AIO都有啥區(qū)別
- Java網(wǎng)絡(luò)IO模型詳解(BIO、NIO、AIO)
- 一文徹底搞懂Java BIO、NIO、AIO的核心區(qū)別
相關(guān)文章
Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容
QSV是一種加密的視頻文件格式。是愛奇藝公司研發(fā)的一種視頻文件格式,這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容,感興趣的可以了解一下2023-03-03
Spring Boot訪問靜態(tài)資源css/js,你真的懂了嗎
在搭建springboot時(shí)經(jīng)常需要在html中訪問一些靜態(tài)資源,很多朋友不清楚如何在 Spring Boot中訪問靜態(tài)資源,本文給大家?guī)?lái)兩種解決方案,感興趣的朋友跟隨小編一起看看吧2021-05-05
詳解Java volatile 內(nèi)存屏障底層原理語(yǔ)義
為了保證內(nèi)存可見性,java 編譯器在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障指令來(lái)禁止特定類型的處理器重排序。為了實(shí)現(xiàn) volatile 內(nèi)存語(yǔ)義,JMM 會(huì)分別限制這兩種類型的重排序類型2021-09-09

