前言
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 的基本概念和理解,如對其他內容感興趣,可繼續關注小編其他文章,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/291625.html
標籤:java
