Java IO 和 NIO 簡(jiǎn)單總結(jié)

先來(lái)看看API的使用很钓。

1. IO 流原理及流的分類

1.1 Java IO

1. I/O是Input/Output的縮寫(xiě)春霍,I/O技術(shù)是非常實(shí)用的技術(shù)翅睛,用于處理數(shù)據(jù)傳輸比默。如讀/寫(xiě)文件,網(wǎng)絡(luò)通訊等驼修。
2. Java程序中殿遂,對(duì)于數(shù)據(jù)的輸入/輸出操作以“流(Stream)”的方式進(jìn)行。
3. java.io包下提供了各種“流”類和接口乙各,用以獲取不同種類的數(shù)據(jù)墨礁,并通過(guò)方法輸入或輸出數(shù)據(jù)
4. 輸入input:讀取外部數(shù)據(jù)(磁盤(pán)、光盤(pán)等存儲(chǔ)設(shè)備的數(shù)據(jù))到程序(內(nèi)存)中
5. 輸出output:將程序(內(nèi)存)數(shù)據(jù)輸出到磁盤(pán)耳峦、光盤(pán)等存儲(chǔ)設(shè)備中

1.2 流的分類

image.png
image.png

節(jié)點(diǎn)流和處理流

節(jié)點(diǎn)流和處理流的區(qū)別和聯(lián)系

  1. 節(jié)點(diǎn)流是底層流/低級(jí)流恩静,直接跟數(shù)據(jù)源相接。
  2. 處理流(包裝流)包裝節(jié)點(diǎn)流蹲坷,既可以消除不同節(jié)點(diǎn)流的實(shí)現(xiàn)差異驶乾,也可以提供更方便的方法來(lái)完成輸入輸出
  3. 處理流(也叫包裝流)對(duì)節(jié)點(diǎn)流進(jìn)行包裝,使用了修飾器設(shè)計(jì)模式循签,不會(huì)直接與數(shù)據(jù)源相連

處理流的功能主要體現(xiàn)在以下兩個(gè)方面:

  1. 性能的提高:主要以增加緩沖的方式來(lái)提高輸入輸出的效率
  2. 操作的便捷:處理流可能提供了一系列便捷的方法來(lái)一次輸入輸出大批量的數(shù)據(jù)级乐,使用更加靈活方便。

來(lái)看看4種處理流:

1.處理流BufferedReader 和BufferedWriter
BufferedReader 和 BufferedWriter 屬于字符流县匠,是按字符來(lái)讀取數(shù)據(jù)的
關(guān)閉時(shí)风科,處理流只需要關(guān)閉外層流即可

下面來(lái)看看BufferedReader使用撒轮。

public class BufferedReader_ {
    public static void main(String[] args) throws Exception {
        String filePath = "e:\\a.java";
        //創(chuàng)建bufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        //讀取
        String line; //按行讀取, 效率高
        //說(shuō)明
        //1. bufferedReader.readLine() 是按行讀取文件
        //2. 當(dāng)返回null 時(shí),表示文件讀取完畢
        while ((line = bufferedReader.readLine()) != null) {
          System.out.println(line);
        }
        //關(guān)閉流, 這里注意贼穆,只需要關(guān)閉BufferedReader 题山,因?yàn)榈讓訒?huì)自動(dòng)的去關(guān)閉節(jié)點(diǎn)流 
        bufferedReader.close();
    }
}

2.處理流BufferedInputStream 和BufferedOutputStream
BufferedInputStream 是字節(jié)流,在創(chuàng)建BufferedInputStream 時(shí)故痊,會(huì)創(chuàng)建一個(gè)內(nèi)部緩沖區(qū)數(shù)組顶瞳。
BufferedOutputStream是字節(jié)流,實(shí)現(xiàn)緩沖的輸出流愕秫,可以將多個(gè)字節(jié)寫(xiě)入底層輸出流中慨菱,而不必對(duì)每次字節(jié)寫(xiě)入調(diào)用底層系統(tǒng)。

image.png

image.png

3.對(duì)象流ObjectInputStream 和ObjectOutputStream
功能:提供了對(duì)基本類型或?qū)ο箢愋偷男蛄谢头葱蛄谢姆椒?br> ObjectOutputStream 提供序列化功能
ObjectInputStream 提供反序列化功能

1.序列化就是在保存數(shù)據(jù)時(shí)豫领,保存數(shù)據(jù)的值和數(shù)據(jù)類型
2.反序列化就是在恢復(fù)數(shù)據(jù)時(shí)抡柿,恢復(fù)數(shù)據(jù)的值和數(shù)據(jù)類型
3.需要讓某個(gè)對(duì)象支持序列化機(jī)制舔琅,則必須讓其類是可序列化的等恐,為了讓某個(gè)類是可序列化的,該類必須實(shí)現(xiàn)接口备蚓。


image.png

4.轉(zhuǎn)換流InputStreamReader 和OutputStreamWriter

image.png

先看一個(gè)文件亂碼問(wèn)題课蔬,引出學(xué)習(xí)轉(zhuǎn)換流必要性。


image.png
//看一個(gè)中文亂碼問(wèn)題
public class CodeQuestion {
    public static void main(String[] args) throws IOException {
    //讀取e:\\a.txt 文件到程序
    //思路
    //1. 創(chuàng)建字符輸入流BufferedReader [處理流]
    //2. 使用BufferedReader 對(duì)象讀取a.txt
    //3. 默認(rèn)情況下郊尝,讀取文件是按照utf-8 編碼
    String filePath = "e:\\a.txt";
    BufferedReader br = new BufferedReader(new FileReader(filePath));
    String s = br.readLine();
    System.out.println("讀取到的內(nèi)容: " + s);
    br.close();
    //InputStreamReader
    //OutputStreamWriter
    }
}

演示使用InputStreamReader 轉(zhuǎn)換流解決中文亂碼問(wèn)題

public class InputStreamReader_ {
  public static void main(String[] args) throws IOException {
  String filePath = "e:\\a.txt";
  //解讀
  //1. 把FileInputStream 轉(zhuǎn)成InputStreamReader
  //2. 指定編碼 gbk
  //InputStreamReader isr = new InputStreamReader(new   FileInputStream(filePath), "gbk"); //3. 把 InputStreamReader   傳入 BufferedReader
  //3. 把InputStreamReader 傳入 BufferedReader
  //BufferedReader br = new BufferedReader(isr);
  //將2 和 3 合在一起
  BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));
  //4. 讀取
  String s = br.readLine();
  System.out.println("讀取內(nèi)容=" + s); 
  //5. 關(guān)閉外層流
  br.close();
  }
}

1.3 Java IO讀寫(xiě)原理

無(wú)論是Socket的讀寫(xiě)還是文件的讀寫(xiě)二跋,在Java層面的應(yīng)用開(kāi)發(fā)或者是linux系統(tǒng)底層開(kāi)發(fā),都屬于輸入input和輸出output的處理流昏,簡(jiǎn)稱為IO讀寫(xiě)扎即。在原理上和處理流程上,都是一致的况凉。區(qū)別在于參數(shù)的不同谚鄙。
用戶程序進(jìn)行IO的讀寫(xiě),基本上會(huì)用到read&write兩大系統(tǒng)調(diào)用刁绒∶朴可能不同操作系統(tǒng),名稱不完全一樣知市,但是功能是一樣的傻盟。
先強(qiáng)調(diào)一個(gè)基礎(chǔ)知識(shí):read系統(tǒng)調(diào)用,并不是把數(shù)據(jù)直接從物理設(shè)備嫂丙,讀數(shù)據(jù)到內(nèi)存娘赴。write系統(tǒng)調(diào)用,也不是直接把數(shù)據(jù)跟啤,寫(xiě)入到物理設(shè)備诽表。
read系統(tǒng)調(diào)用媳叨,是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到進(jìn)程緩沖區(qū);而write系統(tǒng)調(diào)用关顷,是把數(shù)據(jù)從進(jìn)程緩沖區(qū)復(fù)制到內(nèi)核緩沖區(qū)糊秆。這個(gè)兩個(gè)系統(tǒng)調(diào)用,都不負(fù)責(zé)數(shù)據(jù)在內(nèi)核緩沖區(qū)和磁盤(pán)之間的交換议双。底層的讀寫(xiě)交換痘番,是由操作系統(tǒng)kernel內(nèi)核完成的。

操作系統(tǒng)中誰(shuí)負(fù)責(zé)IO拷貝平痰?
DMA 負(fù)責(zé)內(nèi)核間的 IO 傳輸汞舱,CPU 負(fù)責(zé)內(nèi)核和應(yīng)用間的 IO 傳輸。
兩種拷貝類型:
(1)CPU COPY
通過(guò)計(jì)算機(jī)的組成原理我們知道, 內(nèi)存的讀寫(xiě)操作是需要 CPU 的協(xié)調(diào)數(shù)據(jù)總線,地址總線和控制總線來(lái)完成的因此在"拷貝"發(fā)生的時(shí)候,往往需要 CPU 暫妥诠停現(xiàn)有的處理邏輯,來(lái)協(xié)助內(nèi)存的讀寫(xiě)昂芜,這種我們稱為 CPU COPY。CPU COPY 不但占用了 CPU 資源,還占用了總線的帶寬赔蒲。
(2)DMA COPY
DMA(DIRECT MEMORY ACCESS) 是現(xiàn)代計(jì)算機(jī)的重要功能泌神,它有一個(gè)重要特點(diǎn):當(dāng)需要與外設(shè)進(jìn)行數(shù)據(jù)交換時(shí), CPU 只需要初始化這個(gè)動(dòng)作便可以繼續(xù)執(zhí)行其他指令,剩下的數(shù)據(jù)傳輸?shù)膭?dòng)作完全由DMA來(lái)完成可以看到 DMA COPY 是可以避免大量的 CPU 中斷的。
拷貝過(guò)程中會(huì)發(fā)生什么舞虱?
從內(nèi)核態(tài)到用戶態(tài)時(shí)會(huì)發(fā)生上下文切換欢际,上下文切換時(shí)指由用戶態(tài)切換到內(nèi)核態(tài), 以及由內(nèi)核態(tài)切換到用戶態(tài)。
非零拷貝IO流程


https://zhuanlan.zhihu.com/p/430848775

由上圖可以很清晰地看到, 一次 read-send 涉及到了四次拷貝:

硬盤(pán)拷貝到內(nèi)核緩沖區(qū)(DMA COPY)矾兜;
內(nèi)核緩沖區(qū)拷貝到應(yīng)用程序緩沖區(qū)(CPU COPY)损趋;
應(yīng)用程序緩沖區(qū)拷貝到socket緩沖區(qū)(CPU COPY);
socket buf拷貝到網(wǎng)卡的buf(DMA COPY)椅寺。
其中涉及到2次 CPU 中斷, 還有4次的上下文切換浑槽。很明顯,第2次和第3次的的 copy 只是把數(shù)據(jù)復(fù)制到 app buffer 又原封不動(dòng)的復(fù)制回來(lái), 為此帶來(lái)了兩次的 CPU COPY 和兩次上下文切換, 是完全沒(méi)有必要的。

Linux 的零拷貝技術(shù)就是為了優(yōu)化掉這兩次不必要的拷貝返帕。

內(nèi)核緩沖與進(jìn)程緩沖區(qū)

緩沖區(qū)的目的桐玻,是為了減少頻繁的系統(tǒng)IO調(diào)用。大家都知道溉旋,系統(tǒng)調(diào)用需要保存之前的進(jìn)程數(shù)據(jù)和狀態(tài)等信息畸冲,而結(jié)束調(diào)用之后回來(lái)還需要恢復(fù)之前的信息,為了減少這種損耗時(shí)間观腊、也損耗性能的系統(tǒng)調(diào)用邑闲,于是出現(xiàn)了緩沖區(qū)。
有了緩沖區(qū)梧油,操作系統(tǒng)使用read函數(shù)把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到進(jìn)程緩沖區(qū)苫耸,write把數(shù)據(jù)從進(jìn)程緩沖區(qū)復(fù)制到內(nèi)核緩沖區(qū)中。等待緩沖區(qū)達(dá)到一定數(shù)量的時(shí)候儡陨,再進(jìn)行IO的調(diào)用褪子,提升性能量淌。至于什么時(shí)候讀取和存儲(chǔ)則由內(nèi)核來(lái)決定,用戶程序不需要關(guān)心嫌褪。
在linux系統(tǒng)中呀枢,系統(tǒng)內(nèi)核也有個(gè)緩沖區(qū)叫做內(nèi)核緩沖區(qū)。每個(gè)進(jìn)程有自己獨(dú)立的緩沖區(qū)笼痛,叫做進(jìn)程緩沖區(qū)裙秋。
所以,用戶程序的IO讀寫(xiě)程序缨伊,大多數(shù)情況下摘刑,并沒(méi)有進(jìn)行實(shí)際的IO操作,而是在讀寫(xiě)自己的進(jìn)程緩沖區(qū)刻坊。

https://www.cnblogs.com/crazymakercircle/p/10225159.html

2. NIO

NIO:Non-blocking IO 枷恕,非阻塞IO。
2.1 NIO API 簡(jiǎn)單理解
先看看NIO概述谭胚,可以參考這篇
java nio 詳_java NIO 詳解

下面來(lái)簡(jiǎn)單看看MappedByteBuffer徐块,這是NIO包下的一個(gè)類。


https://www.runoob.com/manual/jdk1.6/java.base/java/nio/MappedByteBuffer.html

FileChannel提供了map方法把文件映射到虛擬內(nèi)存漏益,通常情況可以映射整個(gè)文件蛹锰,如果文件比較大深胳,可以進(jìn)行分段映射绰疤。
具體可參考這2篇
深入淺出MappedByteBuffer
MappedByteBuffer的使用

2.2 NIO的零拷貝

NIO的零拷貝由transferTo方法實(shí)現(xiàn)。transferTo方法將數(shù)據(jù)從FileChannel對(duì)象傳送到可寫(xiě)的字節(jié)通道(如Socket Channel等)舞终。在transferTo方法內(nèi)部實(shí)現(xiàn)中轻庆,由native方法transferTo0來(lái)實(shí)現(xiàn),它依賴底層操作系統(tǒng)的支持敛劝。在UNIX和Linux系統(tǒng)中余爆,調(diào)用這個(gè)方法會(huì)引起sendfile()系統(tǒng)(Linux 內(nèi)核2.1開(kāi)始引入一個(gè)叫 sendFile 系統(tǒng)調(diào)用,這個(gè)系統(tǒng)調(diào)用可以在內(nèi)核態(tài)內(nèi)把數(shù)據(jù)從內(nèi)核緩沖區(qū)直接復(fù)制到套接字(SOCKET)緩沖區(qū)內(nèi), 從而可以減少上下文的切換和不必要數(shù)據(jù)的復(fù)制。 具體可看這篇 https://zhuanlan.zhihu.com/p/430848775)調(diào)用夸盟,實(shí)現(xiàn)了數(shù)據(jù)直接從內(nèi)核的讀緩沖區(qū)傳輸?shù)教捉幼志彌_區(qū)蛾方,避免了用戶態(tài)(User-space) 與內(nèi)核態(tài)(Kernel-space) 之間的數(shù)據(jù)拷貝。

https://zhuanlan.zhihu.com/p/430848775

最后數(shù)據(jù)拷貝變成只有兩次 DMA COPY:
1.硬盤(pán)拷貝到內(nèi)核緩沖區(qū)(DMA COPY)上陕;
2.內(nèi)核緩沖區(qū)拷貝到網(wǎng)卡的 buf(DMA COPY)桩砰。

"零拷貝"中的"拷貝"是指操作系統(tǒng)在I/O操作中,將數(shù)據(jù)從一個(gè)內(nèi)存區(qū)域復(fù)制到另外一個(gè)內(nèi)存區(qū)域,而"零"并不是指0次復(fù)制, 更多的是指在用戶態(tài)和內(nèi)核態(tài)之間的復(fù)制是0次释簿。

在不需要進(jìn)行數(shù)據(jù)文件操作時(shí)亚隅,可以使用NIO的零拷貝。但如果既需要IO速度庶溶,又需要進(jìn)行數(shù)據(jù)操作煮纵,則需要使用NIO的直接內(nèi)存映射懂鸵。

2.3 內(nèi)存映射

2.3.1 Linux直接內(nèi)存映射

Linux提供的mmap系統(tǒng)調(diào)用, 它可以將一段用戶空間內(nèi)存映射到內(nèi)核空間, 當(dāng)映射成功后, 用戶對(duì)這段內(nèi)存區(qū)域的修改可以直接反映到內(nèi)核空間;同樣地行疏, 內(nèi)核空間對(duì)這段區(qū)域的修改也直接反映用戶空間匆光。正因?yàn)橛羞@樣的映射關(guān)系, 就不需要在用戶態(tài)(User-space)與內(nèi)核態(tài)(Kernel-space) 之間拷貝數(shù)據(jù), 提高了數(shù)據(jù)傳輸?shù)男誓鹆@就是內(nèi)存直接映射技術(shù)殴穴。

2.3.2 NIO的直接內(nèi)存映射

JDK1.4加入了NIO機(jī)制和直接內(nèi)存,目的是防止Java堆和Native堆之間數(shù)據(jù)復(fù)制帶來(lái)的性能損耗货葬,此后NIO可以使用Native的方式直接在 Native堆分配內(nèi)存采幌。


image.png

直接內(nèi)存的創(chuàng)建
在ByteBuffer有兩個(gè)子類,HeapByteBuffer和DirectByteBuffer震桶。前者是存在于JVM堆中的休傍,后者是存在于Native堆中的。


image.png

申請(qǐng)堆內(nèi)存
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
}

申請(qǐng)直接內(nèi)存

public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity);
}

使用直接內(nèi)存的原因

  • 對(duì)垃圾回收停頓的改善蹲姐。因?yàn)閒ull gc時(shí)磨取,垃圾收集器會(huì)對(duì)所有分配的堆內(nèi)內(nèi)存進(jìn)行掃描,垃圾收集對(duì)Java應(yīng)用造成的影響柴墩,跟堆的大小是成正比的忙厌。過(guò)大的堆會(huì)影響Java應(yīng)用的性能。如果使用堆外內(nèi)存的話江咳,堆外內(nèi)存是直接受操作系統(tǒng)管理逢净。這樣做的結(jié)果就是能保持一個(gè)較小的JVM堆內(nèi)存,以減少垃圾收集對(duì)應(yīng)用的影響歼指。(full gc時(shí)會(huì)觸發(fā)堆外空閑內(nèi)存的回收爹土。)
  • 減少了數(shù)據(jù)從JVM拷貝到native堆的次數(shù),在某些場(chǎng)景下可以提升程序I/O的性能踩身。
  • 可以突破JVM內(nèi)存限制胀茵,操作更多的物理內(nèi)存。

當(dāng)直接內(nèi)存不足時(shí)會(huì)觸發(fā)full gc挟阻,排查full gc的時(shí)候琼娘,一定要考慮。

使用直接內(nèi)存的問(wèn)題

  • 堆外內(nèi)存難以控制附鸽,如果內(nèi)存泄漏脱拼,那么很難排查(VisualVM可以通過(guò)安裝插件來(lái)監(jiān)控堆外內(nèi)存)。
  • 堆外內(nèi)存只能通過(guò)序列化和反序列化來(lái)存儲(chǔ)拒炎,保存對(duì)象速度比堆內(nèi)存慢挪拟,不適合存儲(chǔ)很復(fù)雜的對(duì)象。一般簡(jiǎn)單的對(duì)象或者扁平化的比較適合击你。
  • 直接內(nèi)存的訪問(wèn)速度(讀寫(xiě)方面)會(huì)快于堆內(nèi)存玉组。在申請(qǐng)內(nèi)存空間時(shí)谎柄,堆內(nèi)存速度高于直接內(nèi)存。

使用場(chǎng)景

  • 直接內(nèi)存適合申請(qǐng)次數(shù)少惯雳,訪問(wèn)頻繁的場(chǎng)合朝巫。如果內(nèi)存空間需要頻繁申請(qǐng),則不適合直接內(nèi)存石景。

3.IO與NIO的區(qū)別

IO流是阻塞的,NIO流是不阻塞的往史。

  • Java NIO使我們可以進(jìn)行非阻塞IO操作仗颈。比如說(shuō),單線程中從通道讀取數(shù)據(jù)到buffer椎例,同時(shí)可以繼續(xù)做別的事情挨决,當(dāng)數(shù)據(jù)讀取到buffer中后脖祈,線程再繼續(xù)處理數(shù)據(jù)。寫(xiě)數(shù)據(jù)也是一樣的刷晋。另外或舞,非阻塞寫(xiě)也是如此。一個(gè)線程請(qǐng)求寫(xiě)入一些數(shù)據(jù)到某通道蒙幻,但不需要等待它完全寫(xiě)入,這個(gè)線程同時(shí)可以去做別的事情胆筒。
  • Java IO的各種流是阻塞的邮破。這意味著,當(dāng)一個(gè)線程調(diào)用read() 或 write()時(shí)仆救,該線程被阻塞抒和,直到有一些數(shù)據(jù)被讀取,或數(shù)據(jù)完全寫(xiě)入彤蔽。該線程在此期間不能再干任何事情了摧莽。


    image.png

選擇器(Selectors)
Java NIO的選擇器允許一個(gè)單獨(dú)的線程來(lái)監(jiān)視多個(gè)輸入通道,你可以注冊(cè)多個(gè)通道使用一個(gè)選擇器顿痪,然后使用一個(gè)單獨(dú)的線程來(lái)“選擇”通道:這些通道里已經(jīng)有可以處理的輸入镊辕,或者選擇已準(zhǔn)備寫(xiě)入的通道油够。這種選擇機(jī)制,使得一個(gè)單獨(dú)的線程很容易來(lái)管理多個(gè)通道征懈。

NIO和IO適用場(chǎng)景
如果需要管理同時(shí)打開(kāi)的成千上萬(wàn)個(gè)連接石咬,這些連接每次只是發(fā)送少量的數(shù)據(jù),例如聊天服務(wù)器卖哎,這時(shí)候用NIO處理數(shù)據(jù)可能是個(gè)很好的選擇鬼悠。
而如果只有少量的連接,而這些連接每次要發(fā)送大量的數(shù)據(jù)亏娜,這時(shí)候傳統(tǒng)的IO更合適焕窝。使用哪種處理數(shù)據(jù),需要在數(shù)據(jù)的響應(yīng)等待時(shí)間和檢查緩沖區(qū)數(shù)據(jù)的時(shí)間上作比較來(lái)權(quán)衡選擇维贺。

4. Linux中五種IO模型袜啃,阻塞,非阻塞幸缕,同步群发,異步

  • Blocking IO - 阻塞IO
  • NoneBlocking IO - 非阻塞IO
  • IO multiplexing - IO多路復(fù)用
  • signal driven IO - 信號(hào)驅(qū)動(dòng)IO
  • asynchronous IO - 異步IO

http://www.reibang.com/p/b8203d46895c
由于signal driven IO在實(shí)際使用中并不常用,所以這里只討論剩下的四種IO模型发乔。
在討論之前先說(shuō)明一下IO發(fā)生時(shí)涉及到的對(duì)象和步驟熟妓,對(duì)于一個(gè)network IO,它會(huì)涉及到兩個(gè)系統(tǒng)對(duì)象:

  • application 調(diào)用這個(gè)IO的進(jìn)程
  • kernel 系統(tǒng)內(nèi)核

那他們經(jīng)歷的兩個(gè)交互過(guò)程是:

  • 階段1 wait for data 等待數(shù)據(jù)準(zhǔn)備
  • 階段2 copy data from kernel to user 將數(shù)據(jù)從內(nèi)核拷貝到用戶進(jìn)程中

之所以會(huì)有同步栏尚、異步起愈、阻塞和非阻塞這幾種說(shuō)法就是根據(jù)程序在這兩個(gè)階段的處理方式不同而產(chǎn)生的。了解了這些背景之后译仗,我們就分別針對(duì)四種IO模型進(jìn)行講解抬虽。

1.Blocking IO - 阻塞IO
在linux中,默認(rèn)情況下所有的socket都是blocking纵菌,一個(gè)典型的讀操作流程大概如下圖:

blocking IO

當(dāng)用戶進(jìn)程調(diào)用了recvfrom這個(gè)系統(tǒng)調(diào)用阐污,kernel就開(kāi)始了IO的第一個(gè)階段:準(zhǔn)備數(shù)據(jù)。對(duì)于network IO來(lái)說(shuō)咱圆,很多時(shí)候數(shù)據(jù)在一開(kāi)始還沒(méi)有到達(dá)(比如笛辟,還沒(méi)有收到一個(gè)完整的UDP包),這個(gè)時(shí)候kernel就要等待足夠的數(shù)據(jù)到來(lái)序苏。而在用戶進(jìn)程這邊手幢,整個(gè)進(jìn)程會(huì)被阻塞。當(dāng)kernel一直等到數(shù)據(jù)準(zhǔn)備好了忱详,它就會(huì)將數(shù)據(jù)從kernel中拷貝到用戶內(nèi)存围来,然后kernel返回結(jié)果,用戶進(jìn)程才解除block的狀態(tài),重新運(yùn)行起來(lái)监透。
所以桶错,blocking IO的特點(diǎn)就是在IO執(zhí)行的兩個(gè)階段都被block了。

2.NoneBlockingIO - 非阻塞IO
linux下才漆,可以通過(guò)設(shè)置socket使其變?yōu)閚on-blocking牛曹。當(dāng)對(duì)一個(gè)non-blocking socket執(zhí)行讀操作時(shí),流程是這個(gè)樣子:

NonBlocking IO

從圖中可以看出醇滥,當(dāng)用戶進(jìn)程發(fā)出recvfrom這個(gè)系統(tǒng)調(diào)用后黎比,如果kernel中的數(shù)據(jù)還沒(méi)有準(zhǔn)備好,那么它并不會(huì)block用戶進(jìn)程鸳玩,而是立刻返回一個(gè)結(jié)果(no datagram ready)阅虫。從用戶進(jìn)程角度講 ,它發(fā)起一個(gè)操作后不跟,并沒(méi)有等待颓帝,而是馬上就得到了一個(gè)結(jié)果。用戶進(jìn)程得知數(shù)據(jù)還沒(méi)有準(zhǔn)備好后窝革,它可以每隔一段時(shí)間再次發(fā)送recvfrom操作购城。一旦kernel中的數(shù)據(jù)準(zhǔn)備好了,并且又再次收到了用戶進(jìn)程的system call虐译,那么它馬上就將數(shù)據(jù)拷貝到了用戶內(nèi)存瘪板,然后返回。

所以漆诽,用戶進(jìn)程其實(shí)是需要不斷的主動(dòng)詢問(wèn)kernel數(shù)據(jù)好了沒(méi)有侮攀。

3.IO multiplexing - IO多路復(fù)用
I/O多路復(fù)用(multiplexing)是網(wǎng)絡(luò)編程中最常用的模型,像我們最常用的select厢拭、epoll都屬于這種模型兰英。以select為例:

multiplexing IO

看起來(lái)它與blocking I/O很相似,兩個(gè)階段都阻塞供鸠。但它與blocking I/O的一個(gè)重要區(qū)別就是它可以等待多個(gè)數(shù)據(jù)報(bào)就緒(datagram ready)畦贸,即可以處理多個(gè)連接。這里的select相當(dāng)于一個(gè)“代理”回季,調(diào)用select以后進(jìn)程會(huì)被select阻塞家制,這時(shí)候在內(nèi)核空間內(nèi)select會(huì)監(jiān)聽(tīng)指定的多個(gè)datagram (如socket連接),如果其中任意一個(gè)數(shù)據(jù)就緒了就返回泡一。此時(shí)程序再進(jìn)行數(shù)據(jù)讀取操作,將數(shù)據(jù)拷貝至當(dāng)前進(jìn)程內(nèi)觅廓。由于select可以監(jiān)聽(tīng)多個(gè)socket鼻忠,我們可以用它來(lái)處理多個(gè)連接。

在select模型中每個(gè)socket一般都設(shè)置成non-blocking,雖然等待數(shù)據(jù)階段仍然是阻塞狀態(tài)帖蔓,但是它是被select調(diào)用阻塞的矮瘟,而不是直接被I/O阻塞的。select底層通過(guò)輪詢機(jī)制來(lái)判斷每個(gè)socket讀寫(xiě)是否就緒塑娇。

當(dāng)然select也有一些缺點(diǎn)澈侠,比如底層輪詢機(jī)制會(huì)增加開(kāi)銷、支持的文件描述符數(shù)量過(guò)少等埋酬。為此哨啃,Linux引入了epoll作為select的改進(jìn)版本。

4.asynchronous IO - 異步IO
異步I/O在網(wǎng)絡(luò)編程中幾乎用不到写妥,在File I/O中可能會(huì)用到:

asynchronous IO

這里面的讀取操作的語(yǔ)義與上面的幾種模型都不同拳球。這里的讀取操作(aio_read)會(huì)通知內(nèi)核進(jìn)行讀取操作并將數(shù)據(jù)拷貝至進(jìn)程中,完事后通知進(jìn)程整個(gè)操作全部完成(綁定一個(gè)回調(diào)函數(shù)處理數(shù)據(jù))珍特。讀取操作會(huì)立刻返回祝峻,程序可以進(jìn)行其它的操作,所有的讀取扎筒、拷貝工作都由內(nèi)核去做莱找,做完以后通知進(jìn)程,進(jìn)程調(diào)用綁定的回調(diào)函數(shù)來(lái)處理數(shù)據(jù)嗜桌。

阻塞奥溺、非阻塞,同步和異步

阻塞和非阻塞:

  • 阻塞調(diào)用會(huì)一直等待遠(yuǎn)程數(shù)據(jù)就緒再返回症脂,即上面的 階段1 會(huì)阻塞調(diào)用者谚赎,直到讀取結(jié)束。
  • 而非阻塞無(wú)論在什么情況下都會(huì)立即返回诱篷,雖然非阻塞大部分時(shí)間不會(huì)被block壶唤,但是它仍要求進(jìn)程不斷地去主動(dòng)詢問(wèn)kernel是否準(zhǔn)備好數(shù)據(jù),也需要進(jìn)程主動(dòng)地再次調(diào)用recvfrom來(lái)將數(shù)據(jù)拷貝到用戶內(nèi)存棕所。

同步和異步:

  • 同步方法會(huì)一直阻塞進(jìn)程闸盔,直到I/O操作結(jié)束,注意這里相當(dāng)于上面的階段1琳省,階段2都會(huì)阻塞調(diào)用者迎吵。其中 Blocking IO - 阻塞IO,Nonblocking IO - 非阻塞IO针贬,IO multiplexing - IO多路復(fù)用击费,signal driven IO - 信號(hào)驅(qū)動(dòng)IO 這四種IO都可以歸類為同步IO。
  • 而異步方法不會(huì)阻塞調(diào)用者進(jìn)程桦他,即使是從內(nèi)核空間的緩沖區(qū)將數(shù)據(jù)拷貝到進(jìn)程中這一操作也不會(huì)阻塞進(jìn)程蔫巩,拷貝完畢后內(nèi)核會(huì)通知進(jìn)程數(shù)據(jù)拷貝結(jié)束。

一般的IO相關(guān)API都是同步。

怎樣理解阻塞非阻塞與同步異步的區(qū)別圆仔?怎樣理解阻塞非阻塞與同步異步的區(qū)別垃瞧? - 陳碩的回答 - 知乎
https://www.zhihu.com/question/19732473/answer/26091478
在處理 IO 的時(shí)候,阻塞和非阻塞都是同步 IO坪郭。
只有使用了特殊的 API 才是異步 IO个从。

https://blog.csdn.net/chen8238065/article/details/48315085
同步與異步
同步和異步關(guān)注的是消息通信機(jī)制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發(fā)出一個(gè)調(diào)用時(shí)歪沃,在沒(méi)有得到結(jié)果之前嗦锐,該調(diào)用就不返回。但是一旦調(diào)用返回绸罗,就得到返回值了意推。
換句話說(shuō),就是由調(diào)用者主動(dòng)等待這個(gè)調(diào)用的結(jié)果珊蟀。
而異步則是相反菊值,調(diào)用在發(fā)出之后大渤,這個(gè)調(diào)用就直接返回了祖屏,所以沒(méi)有返回結(jié)果。換句話說(shuō)造虏,當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后磅崭,調(diào)用者不會(huì)立刻得到結(jié)果儿子。而是在調(diào)用發(fā)出后,被調(diào)用者通過(guò)狀態(tài)砸喻、通知來(lái)通知調(diào)用者柔逼,或通過(guò)回調(diào)函數(shù)處理這個(gè)調(diào)用。
舉個(gè)通俗的例子:
你打電話問(wèn)書(shū)店老板有沒(méi)有《分布式系統(tǒng)》這本書(shū)割岛,如果是同步通信機(jī)制愉适,書(shū)店老板會(huì)說(shuō),你稍等癣漆,”我查一下”维咸,然后開(kāi)始查啊查,等查好了(可能是5秒惠爽,也可能是一天)告訴你結(jié)果(返回結(jié)果)癌蓖。
而異步通信機(jī)制,書(shū)店老板直接告訴你我查一下啊婚肆,查好了打電話給你租副,然后直接掛電話了(不返回結(jié)果)。然后查好了较性,他會(huì)主動(dòng)打電話給你附井。在這里老板通過(guò)“回電”這種方式來(lái)回調(diào)讨越。
阻塞與非阻塞
阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息两残,返回值)時(shí)的狀態(tài).
阻塞調(diào)用是指調(diào)用結(jié)果返回之前永毅,當(dāng)前線程會(huì)被掛起。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回人弓。
非阻塞調(diào)用指在不能立刻得到結(jié)果之前沼死,該調(diào)用不會(huì)阻塞當(dāng)前線程。
還是上面的例子:
你打電話問(wèn)書(shū)店老板有沒(méi)有《分布式系統(tǒng)》這本書(shū)崔赌,你如果是阻塞式調(diào)用意蛀,你會(huì)一直把自己“掛起”,直到得到這本書(shū)有沒(méi)有的結(jié)果健芭,如果是非阻塞式調(diào)用县钥,你不管老板有沒(méi)有告訴你,你自己先一邊去玩了慈迈, 當(dāng)然你也要偶爾過(guò)幾分鐘check一下老板有沒(méi)有返回結(jié)果若贮。
在這里阻塞與非阻塞與是否同步異步無(wú)關(guān)。跟老板通過(guò)什么方式回答你結(jié)果無(wú)關(guān)痒留。

同步和異步的例子可參考AIDL的oneway 異步調(diào)用谴麦。

oneway

http://gityuan.com/2016/09/04/binder-start-service/
你(app進(jìn)程)要給遠(yuǎn)方的家人(system_server進(jìn)程)郵寄一封信(transaction), 你需要通過(guò)郵寄員(Binder Driver)來(lái)完成.整個(gè)過(guò)程如下:
1.你把信交給郵寄員(BC_TRANSACTION);
2.郵寄員收到信后, 填一張單子給你作為一份回執(zhí)(BR_TRANSACTION_COMPLETE). 這樣你才放心知道郵遞員已確定接收信, 否則就這樣走了,信到底有沒(méi)有交到郵遞員手里都不知道,這樣的通信實(shí)在太讓人不省心, 長(zhǎng)時(shí)間收不到遠(yuǎn)方家人的回信, 無(wú)法得知是在路的中途信件丟失呢,還是壓根就沒(méi)有交到郵遞員的手里. 所以說(shuō)oneway也得知道信是投遞狀態(tài)是否成功.
3.郵遞員利用交通工具(Binder Driver),將信交給了你的家人(BR_TRANSACTION);
當(dāng)你收到回執(zhí)(BR_TRANSACTION_COMPLETE)時(shí)心里也不期待家人回信, 那么這便是一次oneway的通信過(guò)程.

非oneway

http://gityuan.com/2016/09/04/binder-start-service/
如果你希望家人回信, 那便是非oneway的過(guò)程,在上述步驟2后并不是直接返回,而是繼續(xù)等待著收到家人的回信, 經(jīng)歷前3個(gè)步驟之后繼續(xù)執(zhí)行:
1.家人收到信后, 立馬寫(xiě)了個(gè)回信交給郵遞員BC_REPLY;
2.同樣,郵遞員要寫(xiě)一個(gè)回執(zhí)(BR_TRANSACTION_COMPLETE)給你家人;
3.郵遞員再次利用交通工具(Binder Driver), 將回信成功交到你的手上(BR_REPLY)
這便是一次完成的非oneway通信過(guò)程.

Binder 的執(zhí)行過(guò)程多數(shù)是是同步操作。換句話說(shuō)伸头,通過(guò)Binder去調(diào)用服務(wù)進(jìn)程提供的接口函數(shù)匾效,那么此函數(shù)執(zhí)行結(jié)束時(shí)結(jié)果就已經(jīng)產(chǎn)生,不涉及回調(diào)機(jī)制恤磷。比如用戶使用getService 向ServiceManager 發(fā)起查詢請(qǐng)求一函數(shù)的返回值就是查詢的結(jié)果面哼,意味若用戶不需要提供額外的回調(diào)函數(shù)來(lái)接收結(jié)果。
Binder 是如何做到這一點(diǎn)的呢扫步?可以想到的方法有很多魔策, 其中常見(jiàn)的一種就是讓調(diào)用者進(jìn)程暫時(shí)掛起,直到目標(biāo)進(jìn)程返回結(jié)果后锌妻, Binder 再喚醒等待的進(jìn)程代乃。
因?yàn)橐粋€(gè)transcation 通常涉及兩個(gè)進(jìn)程A 和B , 當(dāng)A 向B 發(fā)送了請(qǐng)求后, B 需要一段時(shí)間來(lái)執(zhí)行:
此時(shí)對(duì)A 來(lái)說(shuō)就是一個(gè)"未完成的操作"一直到B 返回結(jié)果后仿粹, Binder 驅(qū)動(dòng)才會(huì)再次啟動(dòng)A 來(lái)繼續(xù)執(zhí)行搁吓。

像一些系統(tǒng)服務(wù)調(diào)用應(yīng)用進(jìn)程的時(shí)候就會(huì)使用 oneway,比如 AMS 調(diào)用應(yīng)用進(jìn)程啟動(dòng) Activity吭历,這樣就算應(yīng)用進(jìn)程中做了耗時(shí)的任務(wù)堕仔,也不會(huì)阻塞系統(tǒng)服務(wù)的運(yùn)行。

出處:https://blog.csdn.net/Jason_Lee155/article/details/116637925
1.異步調(diào)用
舉個(gè)例子:假如Client端調(diào)用IPlayer.start()晌区,而且Server端的start需要執(zhí)行2秒摩骨,由于定義的接口是異步的通贞,Client端可以快速的執(zhí)行IPlayer.start(),不會(huì)被Server端block住2秒恼五。
2.同步調(diào)用
舉個(gè)例子:假如Client端調(diào)用IPlayer. getVolume()昌罩,而且Server端的getVolume需要執(zhí)行1秒,由于定義的接口是同步的灾馒,Client端在執(zhí)行IPlayer. getVolume()的時(shí)候茎用,會(huì)被Server端block住1秒
3.為什么會(huì)有同步調(diào)用和異步調(diào)用睬罗?
其實(shí)一般使用異步調(diào)用的時(shí)候轨功,Client并不需要得到Server端執(zhí)行Binder服務(wù)的狀態(tài)或者返回值,這時(shí)候使用異步調(diào)用容达,可以有效的提高Client執(zhí)行的效率古涧。

阻塞和非阻塞:

https://www.zhihu.com/question/36529093/answer/67997184
阻塞是進(jìn)程休眠等待內(nèi)核;非阻塞是用戶進(jìn)程立即返回后再輪詢花盐,或者等待信號(hào)或回調(diào)羡滑。輪詢是同步非阻塞,信號(hào)或回調(diào)是異步非阻塞卒暂。

同步不一定阻塞啄栓。

來(lái)簡(jiǎn)單看看epoll

epoll 是 Linux 內(nèi)核的可擴(kuò)展 I/O 事件通知機(jī)制,其最大的特點(diǎn)就是性能優(yōu)異也祠。下圖是 libevent(一個(gè)知名的異步事件處理軟件庫(kù))對(duì) select昙楚,poll,epoll 诈嘿,kqueue 這幾個(gè) I/O 多路復(fù)用技術(shù)做的性能測(cè)試堪旧。

三種輪詢方式select、poll奖亚、epoll淳梦。
I/O多路復(fù)用的本質(zhì)是使用select,poll或者epoll函數(shù),掛起進(jìn)程昔字,當(dāng)一個(gè)或者多個(gè)I/O事件發(fā)生之后爆袍,將控制返回給用戶進(jìn)程。以服務(wù)器編程為例作郭,傳統(tǒng)的多進(jìn)程(多線程)并發(fā)模型陨囊,在處理用戶連接時(shí)都是開(kāi)啟一個(gè)新的線程或者進(jìn)程去處理一個(gè)新的連接,而I/O多路復(fù)用則可以在一個(gè)進(jìn)程(線程)當(dāng)中同時(shí)監(jiān)聽(tīng)多個(gè)I/O事件夹攒,也就是多個(gè)文件描述符蜘醋。select、poll 和 epoll 都是 Linux API 提供的 IO 復(fù)用方式咏尝。

epoll屬于同步非阻塞IO模型压语。 (這是站在IO模型的角度去分類的啸罢,算非阻塞)

雖然I/O多路復(fù)用的函數(shù)也是阻塞的 ,但是I/O多路復(fù)用是阻塞在select胎食,epoll 這樣的系統(tǒng)調(diào)用之上扰才,而沒(méi)有阻塞在真正的I/O系統(tǒng)調(diào)用如recvfrom之上。

https://blog.csdn.net/Jailman/article/details/78498193

總結(jié):

出處:https://www.zhihu.com/question/19732473/answer/241673170

阻塞/非阻塞斥季, 同步/異步的概念要注意討論的上下文训桶。

  • 在進(jìn)程通信層面, 阻塞/非阻塞酣倾, 同步/異步基本是同義詞, 但是需要注意區(qū)分討論的對(duì)象是發(fā)送方還是接收方谤专。
  • 發(fā)送方阻塞/非阻塞(同步/異步)和接收方的阻塞/非阻塞(同步/異步) 是互不影響的躁锡。
  • 在 IO 系統(tǒng)調(diào)用層面( IO system call )層面, 非阻塞 IO 系統(tǒng)調(diào)用 和 異步 IO 系統(tǒng)調(diào)用存在著一定的差別置侍, 它們都不會(huì)阻塞進(jìn)程映之, 但是返回結(jié)果的方式和內(nèi)容有所差別, 但是都屬于非阻塞系統(tǒng)調(diào)用( non-blocing system call )

非阻塞系統(tǒng)調(diào)用(non-blocking I/O system call 與 asynchronous I/O system call) 的存在可以用來(lái)實(shí)現(xiàn)線程級(jí)別的 I/O 并發(fā)蜡坊, 與通過(guò)多進(jìn)程實(shí)現(xiàn)的 I/O 并發(fā)相比可以減少內(nèi)存消耗以及進(jìn)程切換的開(kāi)銷杠输。

進(jìn)程阻塞為什么不占用cpu資源?

工作隊(duì)列
操作系統(tǒng)為了支持多任務(wù)秕衙,實(shí)現(xiàn)了進(jìn)程調(diào)度的功能蠢甲,會(huì)把進(jìn)程分為“運(yùn)行”和“等待”等幾種狀態(tài)。運(yùn)行狀態(tài)是進(jìn)程獲得cpu使用權(quán)据忘,正在執(zhí)行代碼的狀態(tài)鹦牛;等待狀態(tài)是阻塞狀態(tài),比如上述程序運(yùn)行到recv時(shí)勇吊,程序會(huì)從運(yùn)行狀態(tài)變?yōu)榈却隣顟B(tài)曼追,接收到數(shù)據(jù)后又變回運(yùn)行狀態(tài)。操作系統(tǒng)會(huì)分時(shí)執(zhí)行各個(gè)運(yùn)行狀態(tài)的進(jìn)程汉规,由于速度很快礼殊,看上去就像是同時(shí)執(zhí)行多個(gè)任務(wù)。
下圖中的計(jì)算機(jī)中運(yùn)行著A针史、B晶伦、C三個(gè)進(jìn)程,其中進(jìn)程A執(zhí)行著上述基礎(chǔ)網(wǎng)絡(luò)程序悟民,一開(kāi)始坝辫,這3個(gè)進(jìn)程都被操作系統(tǒng)的工作隊(duì)列所引用,處于運(yùn)行狀態(tài)射亏,會(huì)分時(shí)執(zhí)行近忙。

https://zhuanlan.zhihu.com/p/63179839

等待隊(duì)列
當(dāng)進(jìn)程A執(zhí)行到創(chuàng)建socket的語(yǔ)句時(shí)竭业,操作系統(tǒng)會(huì)創(chuàng)建一個(gè)由文件系統(tǒng)管理的socket對(duì)象(如下圖)。這個(gè)socket對(duì)象包含了發(fā)送緩沖區(qū)及舍、接收緩沖區(qū)未辆、等待隊(duì)列等成員。等待隊(duì)列是個(gè)非常重要的結(jié)構(gòu)锯玛,它指向所有需要等待該socket事件的進(jìn)程咐柜。
https://zhuanlan.zhihu.com/p/63179839

當(dāng)程序執(zhí)行到recv時(shí),操作系統(tǒng)會(huì)將進(jìn)程A從工作隊(duì)列移動(dòng)到該socket的等待隊(duì)列中(如下圖)攘残。由于工作隊(duì)列只剩下了進(jìn)程B和C拙友,依據(jù)進(jìn)程調(diào)度,cpu會(huì)輪流執(zhí)行這兩個(gè)進(jìn)程的程序歼郭,不會(huì)執(zhí)行進(jìn)程A的程序遗契。所以進(jìn)程A被阻塞,不會(huì)往下執(zhí)行代碼病曾,也不會(huì)占用cpu資源牍蜂。
https://zhuanlan.zhihu.com/p/63179839

ps:操作系統(tǒng)添加等待隊(duì)列只是添加了對(duì)這個(gè)“等待中”進(jìn)程的引用,以便在接收到數(shù)據(jù)時(shí)獲取進(jìn)程對(duì)象泰涂、將其喚醒鲫竞,而非直接將進(jìn)程管理納入自己之下。上圖為了方便說(shuō)明逼蒙,直接將進(jìn)程掛到等待隊(duì)列之下从绘。

阻塞和喚醒進(jìn)程

假設(shè)計(jì)算機(jī)中正在運(yùn)行進(jìn)程A和進(jìn)程B,在某時(shí)刻進(jìn)程A運(yùn)行到了epoll_wait語(yǔ)句其做。如下圖所示顶考,內(nèi)核會(huì)將進(jìn)程A放入eventpoll的等待隊(duì)列中,阻塞進(jìn)程妖泄。
epoll_wait阻塞進(jìn)程如下圖:

https://zhuanlan.zhihu.com/p/64746509

當(dāng)socket接收到數(shù)據(jù)驹沿,中斷程序一方面修改rdlist,另一方面喚醒eventpoll等待隊(duì)列中的進(jìn)程蹈胡,進(jìn)程A再次進(jìn)入運(yùn)行狀態(tài)(如下圖)渊季。也因?yàn)閞dlist的存在,進(jìn)程A可以知道哪些socket發(fā)生了變化罚渐。
epoll喚醒進(jìn)程
https://zhuanlan.zhihu.com/p/64746509

epoll 的整個(gè)工作流程


https://zhuanlan.zhihu.com/p/361750240

參考:
深入理解epoll背后的原理
徹底理解Android Binder通信架構(gòu)
圖解 | 深入揭秘 epoll 是如何實(shí)現(xiàn) IO 多路復(fù)用的却汉!
如果這篇文章說(shuō)不清e(cuò)poll的本質(zhì),那就過(guò)來(lái)掐死我吧荷并! (1)
如果這篇文章說(shuō)不清e(cuò)poll的本質(zhì)合砂,那就過(guò)來(lái)掐死我吧! (3)

關(guān)于epoll的IO模型是同步異步的一次糾結(jié)過(guò)程
linux 下進(jìn)程間的同步機(jī)制有哪些
怎樣理解阻塞非阻塞與同步異步的區(qū)別源织?
關(guān)于同步翩伪,異步微猖,阻塞,非阻塞缘屹,IOCP/epoll,select/poll,AIO ,NIO ,BIO的總結(jié)
IO多路復(fù)用的本質(zhì)(select凛剥、poll、epoll)
Socket的三種輪詢方式select轻姿、poll犁珠、epoll之間的區(qū)別
阻塞&非阻塞和同步&非同步
一篇文章讀懂阻塞,非阻塞互亮,同步犁享,異步
IO多路復(fù)用的三種機(jī)制Select,Poll胳挎,Epoll

《韓順平_循序漸進(jìn)學(xué)Java零基礎(chǔ)》第19章IO流
Java IO與NIO的區(qū)別
NIO效率高的原理之零拷貝與直接內(nèi)存映射
深入淺出MappedByteBuffer
Camera Buffer Management

java nio 詳_java NIO 詳解
10分鐘看懂饼疙, Java NIO 底層原理
一文徹底揭秘linux操作系統(tǒng)之「零拷貝」!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慕爬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屏积,更是在濱河造成了極大的恐慌医窿,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炊林,死亡現(xiàn)場(chǎng)離奇詭異姥卢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)渣聚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)独榴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奕枝,你說(shuō)我怎么就攤上這事棺榔。” “怎么了隘道?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵症歇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谭梗,道長(zhǎng)忘晤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任激捏,我火速辦了婚禮设塔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘远舅。我一直安慰自己闰蛔,他們只是感情好痕钢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著钞护,像睡著了一般盖喷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上难咕,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天课梳,我揣著相機(jī)與錄音,去河邊找鬼余佃。 笑死暮刃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爆土。 我是一名探鬼主播椭懊,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼步势!你這毒婦竟也來(lái)了氧猬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坏瘩,失蹤者是張志新(化名)和其女友劉穎盅抚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體倔矾,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妄均,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哪自。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丰包。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖壤巷,靈堂內(nèi)的尸體忽然破棺而出邑彪,到底是詐尸還是另有隱情,我是刑警寧澤隙笆,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布锌蓄,位于F島的核電站,受9級(jí)特大地震影響撑柔,放射性物質(zhì)發(fā)生泄漏瘸爽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一铅忿、第九天 我趴在偏房一處隱蔽的房頂上張望剪决。 院中可真熱鬧,春花似錦、人聲如沸柑潦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)渗鬼。三九已至览露,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間譬胎,已是汗流浹背差牛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留堰乔,地道東北人偏化。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像镐侯,于是被迫代替她去往敵國(guó)和親侦讨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容