Java之IO模型


首先來看一下同步與異步的概念:

  1.同步是指當前端發起一次操作請求時,只有后台執行完所有的代碼操作才會給前端返回值。

  2.異步是將前端發回的消息加入消息隊列,並且立刻給前端返回請求,告訴用戶可以離開當前頁面去做別的事情。當后台處理完成,操作系統會通知事件和回調機制等通知相應的縣城進行后續操作。

 同步和異步最大的區別在於:一個需要等待,一個不需要等待。

接下來解釋一下常見的IO模型:

  阻塞IO模型(最傳統的IO模型):在讀寫數據過程中會發生阻塞現象。當用戶線程發出IO請求之后,內核會去查看數據是否就緒,如果沒有就緒就會等待數據就緒,而用戶線程就會處於阻塞狀態,用戶線程交出CPU。當數據就緒之后,並返回結果給用戶線程,用戶線程才解除block狀態。

  典型的阻塞IO模型的例子為:data=socket.read();如果數據沒有就緒,就會一直阻塞在read方法。

  非阻塞IO模型:當用戶線程發起read操作后,並不需要等待,而是馬上就得到一個結果。如果結果是error時,它就知道數據還沒有准備好,於是它可以再次發送read操作。一旦內核中的數據准備好了,並且又再次收到了用戶線程的請求,那么它馬上就將數據拷貝到用戶線程,然后返回。

  在非阻塞IO模型中,用戶線程需要不斷地詢問內核數據是否就緒,也就是說非阻塞IO不會交出CPU,而是一直占用CPU。

  典型的非阻塞IO模型一般如下:

1 while(true){ 2     data = socket.read(); 3     if(data!= error){    //處理數據
4         break; 5  } 6 }

 

  多路復用IO模型:NIO實際上就是多路復用IO。在多路復用IO模型中,會有一個線程不斷去輪詢多個socket的狀態,只有當socket真正有讀寫事件時,才會調用實際的IO讀寫操作。多路復用IO模式,通過一個線程就可以管理多個socket,不需要建立新的進程或線程,也不必維護這些線程和進程,只有當socket真正有讀寫事件發生時才會占用資源來進行實際的讀寫操作。所以他大大減少了資源占用。因此,多路復用IO適合連接數比較多的情況。

  在NIO中,通過selector.select()去查詢每個通道是否有到達事件,如果沒有則一直阻塞在那里,因此這種方式會導致線程阻塞。

  多路復用IO為何比非阻塞IO的效率高?

   答:是因為在非阻塞IO中,不斷地去詢問socket狀態是通過用戶線程去進行的,而在多路復用IO中,輪詢每個socket狀態是在內核進行的,效率比用戶線程要高。不過要注意的是,多路復用IO模型是通過輪詢的方式來檢測是否有事件到達,並且對於到達的時間逐一進行響應。因此對於多路復用IO模型來說,一旦事件響應體很大,那么就會導致后續的事件遲遲得不到處理並且會影響新的事件輪詢。

  信號驅動IO模型:在信號驅動IO中,當用戶線程發起一個IO請求操作,會給對應的socket注冊一個信號數,然后用戶線程會繼續執行,當內核數據就緒時會發送一個信號給用戶線程,用戶線程接收到信號后,便在信號函數中調用IO讀寫操作來進行實際的IO請求操作。

  異步IO模型:異步IO模型是理想的IO模型。在異步IO模型中,當用戶線程發起read操作后,就可以開始去做別的事情。另一方面,從內核的角度,當它收到一個asynchronous read之后,它會立刻返回,說明read請求已經成功發起了,因此不會對用戶線程產生任何block。然后內核會等待數據准備完成,將數據拷貝到用戶線程,當這一切都完成后,內核會給用戶線程發送一個信號,告訴它read操作完成了。

  在異步IO模型中,IO操作的兩個階段都不會阻塞用戶線程,這兩個階段都是由內核自動完成,然后發送一個信號告知用戶線程操作已經完成。用戶線程中不需要再次調用IO函數進行具體的讀寫。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM