Java IO對大多數(shù)Java程序員來說是熟悉又陌生,熟悉的是感覺到處都有它的身影,小到簡單的讀取文件,大到各種服務(wù)器的應(yīng)用,陌生的是Java IO背后到底是一個怎樣的機制,今天就讓我們?nèi)チ私庖幌逻@位老朋友吧。本文不講解Java IO如何具體使用,有這方面需求的同學可以自己查下。
IO模型要說IO,就不得不說IO模型,IO模型大家都有所了解,同步異步,阻塞非阻塞什么的,總的來說IO模型可分為以下五種:
阻塞IO
非阻塞IO
多路復用IO
信號驅(qū)動IO
異步IO
那么這幾種IO都有什么區(qū)別呢?下面我們一一來看,每種模型我都會舉一個適當?shù)睦又诶斫猓?/p> 1.阻塞IO
阻塞IO相信大家都最熟悉了,線程發(fā)起一個IO請求,直到有結(jié)果返回,否則則一直阻塞等待,比如我們平常常見的阻塞數(shù)據(jù)庫操作,網(wǎng)絡(luò)IO等。
小明阻塞IO吃飯:
五年前一天周末,小明和朋友一起去商場的外婆家吃飯,到店后發(fā)現(xiàn)排隊的人超多,所以他就領(lǐng)了一個號碼,然后他和朋友就坐在旁邊等候,一直等著服務(wù)員叫他們的號,也不能做其他事,過了一個多小時終于輪到他們了,然后他們進店點菜,又得等待上菜,最后他們吃飯總共花了兩個小時;
關(guān)鍵部分:
等待座位吃飯:一直阻塞,直到有座位
等待上菜:一直阻塞,直到有菜(假設(shè)菜上齊了再吃)
沒什么說的,反正就是一直等,反應(yīng)到程序中就是一直阻塞,而一個IO請求需要一個線程,可想而知當有大量的IO請求,線程的創(chuàng)建和銷毀,線程間的切換,線程所占用的資源等等要耗費多少時間和資源,系統(tǒng)的性能會有多差。
2.非阻塞IO非阻塞IO和阻塞IO的最大區(qū)別就在于線程發(fā)起一個IO請求,不會一直堵塞直到有數(shù)據(jù),而是不斷的檢查是否已有數(shù)據(jù),若有數(shù)據(jù)則讀取數(shù)據(jù)。
小明非阻塞IO吃飯:
有了第一次的教訓,小明學乖了,他在拿到后不再傻傻的等著,而是去外婆家旁邊逛了逛,每過3分鐘他就會回來,然后跑到前臺去詢問服務(wù)員輪到他了嗎?不幸的是,排隊的人超多,直到過了半個多小時后才輪到他進店吃飯,期間他大概問了十幾次,他們進店點菜,又得等待上菜,最后他們吃飯總共花了兩個小時,基本也沒做啥其他事;
關(guān)鍵部分:
領(lǐng)號后詢問是否輪到他:非阻塞,非詢問期間可以做點別的事,但也不做了啥大事
等待上菜:一直阻塞,直到有菜(假設(shè)菜上齊了再吃)
總的來說非阻塞IO的非阻塞主要體現(xiàn)在不需要一直等待到有數(shù)據(jù),當然讀數(shù)據(jù)那部分操作還是阻塞的,另外這種非阻塞模式需要用戶線程自己不斷詢問檢查,其實效率也不是太高,實際編程中運用的也不多。
3.多路復用IO既然上面我們說到非阻塞IO的缺點,那么有沒有什么方式改進呢?答案是當然有,那就是多路復用IO,我理解的它的特點就是復用,首先它也是一種非阻塞IO的模型,只不過上面說到輪詢的方式用了不同的方式處理了,當一個線程發(fā)起IO請求,系統(tǒng)會將它注冊到一個多帶帶管理IO請求的一個線程,之后該IO的相關(guān)操作的通知狀態(tài)都有這個管理IO請求的線程處理,Java 1.4發(fā)布的NIO就是這種模式,我們可以大致來看一下它的流程:
// 打開服務(wù)器套接字通道 ServerSocketChannel ssc = ServerSocketChannel.open(); // 服務(wù)器配置為非阻塞 ssc.configureBlocking(false); // 進行服務(wù)的綁定 ssc.bind(new InetSocketAddress("localhost", 8008)); // 這里的selector就相當于多帶帶管理IO請求的線程 Selector selector = Selector.open(); // 注冊到selector,等待連接 ssc.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(); //為IO請求去輪詢狀態(tài) Setkeys = selector.selectedKeys(); //多個IO請求的狀態(tài) Iterator keyIterator = keys.iterator(); while (keyIterator.hasNext()) { //依次處理IO請求 SelectionKey key = keyIterator.next(); doThing(key) ... } }
可以看出Java NIO的模式就是多路復用IO模型的應(yīng)用。
小明多路復用IO吃飯:
隨著生意越來越好,外婆家發(fā)現(xiàn)好多顧客都堵在門口等待吃飯,等待區(qū)都站不下來人了,,思來想去,外婆家準備請一個人專門來維護顧客的排隊請求,這樣顧客取號后,就不用堵在門口了,我們叫他小A,小明這次取號后,將自己的相關(guān)信息告訴小A,并從小A那里獲得了一個GPS(用于小A能快速找到小明,假設(shè)有了GPS后,小A能秒速找到小明),然后小明就跟朋友們開心的去逛商場,看看MM,買買衣服,而小A則不斷的觀察店里的情況,當有空座位出現(xiàn)的時候,他便會按照相關(guān)信息找到具體的顧客,將其帶回進行用餐,但他們進店點菜,還得等待上菜,最后他們吃飯總共花了兩個小時,但是他們不再需要排隊等位,而是去做一些其他的事。
關(guān)鍵部分:
領(lǐng)號后委托給小A,小A觀察到有空位后帶回小明:非阻塞,領(lǐng)號后可以安心去做自己的事,不用擔心錯過
等待上菜:一直阻塞,直到有菜(假設(shè)菜上齊了再吃)
多路復用IO可以看成普通非阻塞IO的升級版,也是目前Java編程中用到比較多的IO模型,它的優(yōu)勢在于可以處理大量的IO請求,用一個線程管理所有的IO請求,無需像阻塞IO和非阻塞IO一樣,每個IO需要一個線程處理,提升了系統(tǒng)的吞吐量。
4.信號驅(qū)動IO信號驅(qū)動IO相對于以上幾種模型最大的特點就是它支持內(nèi)核信號通知,線程在發(fā)起一個IO請求后,會注冊一個信號函數(shù),然后內(nèi)核在確認數(shù)據(jù)可讀了,便會給相應(yīng)的線程發(fā)送通知,讓其進行具體IO讀寫操作。
小明信號驅(qū)動IO吃飯:
又了一段時間,外婆家通過使用復用IO模式緩解了排隊擁擠的情況,但是覺得還要請一個人專門維護隊列,感覺不劃算,那么有沒有一種更好的方式呢?經(jīng)過一天的苦思冥想,外婆家的經(jīng)理又想出一個好辦法,讓每個顧客在領(lǐng)完號后,關(guān)注一下外婆家的公眾號,然后顧客就可以去做別的事了,定時或者當排隊信息發(fā)生改變時給顧客發(fā)送通知,告知他現(xiàn)在的排隊序號或者輪到他吃飯了,顧客可以根據(jù)相應(yīng)的信息做相應(yīng)的行為,比如快輪到了就開始往店里走(實際程序中并不一定有這種狀態(tài),這里只是大概模擬),或者輪到自己了然后進店吃飯,他們?nèi)匀徊挥门抨牭任唬侨プ鲆恍┢渌氖隆?/p>
關(guān)鍵部分:
領(lǐng)號后關(guān)注公眾號,注冊關(guān)系:非阻塞,領(lǐng)號后可以安心去做自己的事,不用擔心錯過
等待上菜:一直阻塞,直到有菜(假設(shè)菜上齊了再吃)
就實際來說,信號驅(qū)動IO用的并不多,因為信號驅(qū)動IO底層是使用SIGIO信號,所以它主要使用在UDP協(xié)議上,因為UDP產(chǎn)生SIGIO信號的時候只有兩種可能:
1.要么數(shù)據(jù)到達
2.發(fā)生錯誤
但相對TCP來說,產(chǎn)生SIGIO信號的地方太多了,比如請求連接,確認,斷開,錯誤等等,所以我們很難根據(jù)SIGIO信號判斷到底發(fā)生了什么。
5.異步IO以上四種IO其實都還是同步IO,因為它們在讀寫數(shù)據(jù)時都是阻塞的,異步IO相較于它們最大的特點是它讀寫數(shù)據(jù)的時候也是非阻塞的,用戶線程在發(fā)起一個IO請求的時候,除了給內(nèi)核線程傳遞具體的IO請求外,還會給其傳遞數(shù)據(jù)緩沖區(qū),回調(diào)函數(shù)通知等內(nèi)容,然后用戶線程就繼續(xù)執(zhí)行,等到內(nèi)核線程發(fā)起相應(yīng)通知的時候,說明數(shù)據(jù)已經(jīng)準備就緒,用戶線程直接使用即可,無需再阻塞從內(nèi)核拷貝數(shù)據(jù)到用戶線程。
小明異步IO吃飯:
有過了一段時間,小明又想吃外婆家了,但是這個周末他并不想出門,他突然在網(wǎng)上看到新聞?wù)f外婆家竟然可以叫外賣,小明高興壞了,他馬上打電話給外婆家,告訴它自己想要吃哪些菜(相當于IO請求所需要的數(shù)據(jù)),然后將自己的聯(lián)系號碼(相當于回調(diào)通知)和住址(相當于數(shù)據(jù)緩沖區(qū))也告訴它,然后就掛掉電話,開心的做去打游戲了,過了半個小時后,手機響起,告知外賣已經(jīng)到了,小明開門取外賣就可以直接開吃了。整個過程小明直到吃飯都沒有等待阻塞。
關(guān)鍵部分:
叫外賣并提供相應(yīng)的信息:非阻塞,打完電話后做自己的事
通知外賣到了:直接開門取外賣直接開吃,非阻塞
我們可以看出,異步IO才是真正的異步,因為它連數(shù)據(jù)拷貝這個過程都是非阻塞的,用戶線程根本不用關(guān)心數(shù)據(jù)的讀寫等操作,只需等待內(nèi)核線程通知后,直接處理數(shù)據(jù)即可,當然異步IO需要系統(tǒng)內(nèi)核支持,比如Linux中的AIO和Windows中的IOCP,但是也可以通過多線程跟阻塞I/O模擬異步IO,比如可以在多路復用IO模型上進行相應(yīng)的改變,另外也有現(xiàn)有的實現(xiàn),比如異步I/O的庫:libeio
最后用一張圖總體概括一下Java IO(圖片來自美團技術(shù)博客):
Java IO概圖:
因為后續(xù)會講到Java NIO,所以我們需要了解操作系統(tǒng)是如何支持多路復用IO的,Linux中支持支持三種多路IO復用機制,分別是select、poll和epoll,本來這里我想自己寫的,但查閱了相應(yīng)的一些資料后,發(fā)現(xiàn)自己的水平還是不夠,這里我不準備班門弄斧了,因為我找到了很多寫的比較好的文章,這里就給大家列一下,僅供參考:
Linux系統(tǒng)編程——I/O多路復用select、poll、epoll的區(qū)別使用
聊聊IO多路復用之select、poll、epoll詳解
IO 多路復用是什么意思?
總結(jié)這篇文章主要講了最基礎(chǔ)的IO模型,不過我認為最基礎(chǔ)的往往是最重要的,只有理解了基礎(chǔ)的原理,才能對基于它們實現(xiàn)的類庫或者工具有更加深刻的認識,下一篇文章將會主要講一下基于多路復用IO的Java NIO,敬請期待。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67882.html
摘要:綁定完成后允許套接字進行連接并等待連接。服務(wù)端根據(jù)報文返回響應(yīng),并關(guān)閉連接。單線程服務(wù)器多進程及多線程服務(wù)器復用服務(wù)器復用的多線程服務(wù)器單線程服務(wù)器一次只處理一個請求,直到其完成為止。 前言 本篇文章將涉及以下內(nèi)容: IO實現(xiàn)Java Socket通信 NIO實現(xiàn)Java Socket通信 閱讀本文之前最好了解過: Java IO Java NIO Java Concurrenc...
0.Why Zipkin 隨著業(yè)務(wù)發(fā)展,系統(tǒng)拆分導致系統(tǒng)調(diào)用鏈路愈發(fā)復雜一個前端請求可能最終需要調(diào)用很多次后端服務(wù)才能完成,當整個請求變慢或不可用時,我們是無法得知該請求是由某個或某些后端服務(wù)引起的,這時就需要解決如何快讀定位服務(wù)故障點,以對癥下藥。于是就有了分布式系統(tǒng)調(diào)用跟蹤的誕生。而zipkin就是開源分布式系統(tǒng)調(diào)用跟蹤的佼佼者 zipkin基于google-Dapper的論文有興趣的可以看下...
時間:2017年07月11日星期二說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:無學習源碼:https://github.com/zccodere/s... 第一章:應(yīng)用場景 1-1 多對多的應(yīng)用場景 案例分析:企業(yè)項目開發(fā)過程中 一個項目可由多個員工參與開發(fā) 一個員工可同時參與開發(fā)多個項目 示意圖 showImg(https://segmentfau...
摘要:而用于主線程池的屬性都定義在中本篇只是簡單介紹了一下引導類的配置屬性,下一篇我將詳細介紹服務(wù)端引導類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡稱NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...
閱讀 2307·2023-04-25 14:17
閱讀 1515·2021-11-23 10:02
閱讀 2170·2021-11-23 09:51
閱讀 873·2021-10-14 09:49
閱讀 3384·2021-10-11 10:57
閱讀 2921·2021-09-24 09:47
閱讀 3046·2021-08-24 10:00
閱讀 2298·2019-08-29 18:46