Java IO特性
1. BIO
阻塞 IO 模型
最傳統的一種 IO 模型,即在讀寫資料過程中會發生阻塞現象。當使用者線程發出 IO請求之後,核心會去檢視資料是否就緒,如果沒有就緒就會等待資料就緒,而使用者線程就會處于阻塞狀态,使用者線程交出CPU。當資料就緒之後,核心會将資料拷貝到使用者線程,并傳回結果給使用者線程,使用者線程才解除 block 狀态。典型的阻塞 IO模型的例子為:data = socket.read();如果資料沒有就緒,就會一直阻塞在 read 方法。
非阻塞 IO 模型
當使用者線程發起一個 read 操作後,并不需要等待,而是馬上就得到了一個結果。如果結果是一個error時,它就知道資料還沒有準備好,于是它可以再次發送 read操作。一旦核心中的資料準備好了,并且又再次收到了使用者線程的請求,那麼它馬上就将資料拷貝到了使用者線程,然後傳回。是以事實上,在非阻塞 IO模型中,使用者線程需要不斷地詢問核心資料是否就緒,也就說非阻塞 IO不會交出 CPU,而會一直占用 CPU。
2. NIO
多路複用 IO 模型是目前使用得比較多的模型。Java NIO 實際上就是多路複用 IO。在多路複用 IO模型中,會有一個線程不斷去輪詢多個socket 的狀态,隻有當 socket 真正有讀寫事件時,才真正調用實際的 IO 讀寫操作。因為在多路複用 IO模型中,隻需要使用一個線程就可以管理多個socket,系統不需要建立新的程序或者線程,也不必維護這些線程和程序,并且隻有在真正有socket讀寫事件進行時,才會使用 IO 資源,是以它大大減少了資源占用。在 Java NIO 中,是通過selector.select()去查詢每個通道是否有到達事件,如果沒有事件,則一直阻塞在那裡,是以這種方式會導緻使用者線程的阻塞。多路複用IO 模式,通過一個線程就可以管理多個 socket,隻有當socket 真正有讀寫事件發生才會占用資源來進行實際的讀寫操作。是以,多路複用IO 比較适合連接配接數比較多的情況。另外多路複用 IO 為何比非阻塞 IO 模型的效率高是因為在非阻塞 IO 中,不斷地詢問 socket狀态時通過使用者線程去進行的,而在多路複用 IO 中,輪詢每個 socket 狀态是核心在進行的,這個效率要比使用者線程要高的多。
不過要注意的是,多路複用 IO 模型是通過輪詢的方式來檢測是否有事件到達,并且對到達的事件逐一進行響應。是以對于多路複用 IO模型來說,一旦事件響應體很大,那麼就會導緻後續的事件遲遲得不到處理,并且會影響新的事件輪詢。
3. AIO
異步 IO 模型才是最理想的 IO 模型,在異步 IO 模型中,當使用者線程發起 read操作之後,立刻就可以開始去做其它的事。而另一方面,從核心的角度,當它受到一個 asynchronous read 之後,它會立刻傳回,說明read 請求已經成功發起了,是以不會對使用者線程産生任何 block。然後,核心會等待資料準備完成,然後将資料拷貝到使用者線程,當這一切都完成之後,核心會給使用者線程發送一個信号,告訴它 read操作完成了。也就說使用者線程完全不需要實際的整個 IO 操作是如何進行的,隻需要先發起一個請求,當接收核心傳回的成功信号時表示 IO操作已經完成,可以直接去使用資料了。也就說在異步 IO 模型中,IO操作的兩個階段都不會阻塞使用者線程,這兩個階段都是由核心自動完成,然後發送一個信号告知使用者線程操作已完成。使用者線程中不需要再次調用 IO函數進行具體的讀寫。這點是和信号驅動模型有所不同的,在信号驅動模型中,當使用者線程接收到信号表示資料已經就緒,然後需要使用者線程調用 IO函數進行實際的讀寫操作;而在異步 IO 模型中,收到信号表示 IO 操作已經完成,不需要再在使用者線程中調用 IO 函數進行實際的讀寫操作。
JavaGuide總結