1. 程式人生 > >從JAVA多執行緒理解到叢集分散式和網路設計的淺析

從JAVA多執行緒理解到叢集分散式和網路設計的淺析

由於最近工作原因,很久沒有在CSDN上留下些啥,今天在這些篇文章,是關於java多執行緒的。

對於JAVA多執行緒的應用非常廣泛,現在的系統沒有多執行緒幾乎什麼也做不了,很多時候我們在何種場合如何應用多執行緒成為一種首先需要選擇的問題,另外關於java多執行緒的知識也是非常的多,本文中先介紹和說明一些常用的,在後續文章中如果有必要再說明更加複雜的吧,本文主要說明多執行緒的一下幾個內容:

1在應用開發中什麼時候選擇多執行緒?

2、多執行緒應該注意些什麼?

3、狀態轉換控制,如何解決死鎖?

4、如何設計一個具有可擴充套件性的多執行緒處理器?

5、多執行緒聯想:在多主機下的擴充套件-

叢集?

6WEB應用的多執行緒以及長連線原理。

1、在應用開發中什麼時候選擇多執行緒。

在前序的文章中已經簡單提及到過一些關於多執行緒應用的文章,通過對web的一些執行緒控制對下載流量的控制,其實那只是雕蟲小技,也存在很多的問題需要去解決,不過面對使用者量不大的人群一般問題不大而已。

多執行緒在生活中的體現就是將多個同樣很多事情交給多個人來並行的完成,而中間有一個主執行緒起到排程者的作用,執行者可以強制依賴於主執行緒的存在而存在,也可以讓主執行緒依賴於自身;曾經我聽很多人說過如果你的機器是單CPU,多執行緒沒有意義,其實我並不這麼認為,以為內單個CPU只能證明線上程被排程的瞬間只能同時執行一條最底層的命令,而並不代表不可以在

CPU的徵用上提高效率,一個是記憶體級別的,而另一個是CPU級別的,效率上仍然存在很大差距的;(這個可以讓一個程式單執行緒去迴圈10億次(每次自增1),和讓十個執行緒獨立執行1億次也是同樣的動作,記住這裡不要將每條資料System.out.println出來,一個是機器扛不住,另一個是這裡會對測試資料產生影響,因為這個方法我前面的文章中已經說明會產生阻塞,尤其是在併發情況下的阻塞,即使在單CPU下結果肯定也是有很大差距的,我這暫時沒有單核的PC機器,所以沒法得到一些測試結果資料給大家,請有條件的朋友自己測試一下)。

在現在的系統中無時無刻都離不開多執行緒的思想,包括叢集、分散式都可以理解為多執行緒的一種原理,那麼什麼是多執行緒的原理呢?多執行緒和多程序的是什麼呢?

其實要實現分佈最簡單的思想就是多程序,其實類似於在系統分隔過程中的一種垂直分隔,將不同業務的系統分佈在不同的節點上執行,他們彼此互不干擾,而多程序的申請、釋放資源各方面的開銷都很大,而且佔用資源並非CPU級別的,而執行緒是屬於程序內部更細節的內容,一個程序內部可以分配N個執行緒,這些執行緒會並行的徵用CPU資源,如果你的機器是多核的處理器,併發將會帶來異常的效能提升,其實原理上就是在有限的資源下,如何發揮出最大的效能優勢(但是一定是資源有一定餘量的情況下,正所謂做事不能做得太絕)。

java中常用於實現多執行緒的方法有3中:

    1、繼承於Thread類,重寫run方法

    2、實現Runable介面,實現run方法

    3、實現Callable介面,實現call方法(具有返回值)

至於呼叫的方法多種多樣,可以直接用start啟動,也可以使用java.util.concurrent.Executors來建立執行緒池來完成,建立的執行緒池也主要分為:

   1Executors.newSingleThreadScheduledExecutor() 建立一個順序執行的執行緒池,你在run方法內部無需使用synchronized來同步,因為它本身是順序的。

   2Executors.newCachedThreadPool()建立一個執行緒池,執行緒會並行的去執行它。

   3Executors.newFixedThreadPool(10)建立大小為10的一個執行緒池,這個執行緒池最多建立長度為10的佇列,如果超過10個,就最多有10個執行緒在執行,即可以控制執行緒的數量,也可以讓其並行執行。

如果你的系統是一個WEB應用,建議儘量不要再web應用中做多執行緒,因為這部分執行緒控制主要是由web容器控制的,如果在非得必要的情況下建立,儘量建立較少,或者儘量將可以不太頻繁排程的執行緒使用完後直接釋放掉,哪怕下次重建也無所謂。

如果你的多執行緒序是獨立執行的,專門用於接受和和處理一些訊息,那麼我相信最少有一個執行緒是不斷探測的(有很多程式會先休眠一點時間,如:TimeUnit.MINUTES.sleep(SLEEP_TIME)此方法是按照毫秒級進行休眠一段時間),這類程式,最好將執行緒設定為後臺執行緒(setDaemon(true),一定要線上程呼叫run之前呼叫該方法有效),後臺執行緒和非後臺執行緒最大的區別在於:後臺執行緒在所有非後臺執行緒死掉後,後臺執行緒自動會被殺死和回收;而正如你寫其他的多執行緒程式,即使你的main方法完成(主執行緒),但是在main中申請的子執行緒沒有完成,程式仍然不會結束。

總的來說,其實幾乎每時每刻寫的程式碼都是多執行緒的,只是很多事情容器幫助我們完成了,即使編寫本地的AWTSWING,也在很多控制處理中式非同步的,只是這種非同步相對較少,更多的非同步可以由程式去編寫,自定義的多執行緒一般用於在獨立於前段容器應用的後臺處理中。為什麼類似web應用的前端會把多執行緒早就處理好呢,一個是因為為了減少程式和bug,另外一個就是要寫好多執行緒的確不容易,這樣會使得程式設計師去關心更多沒有必要關心的東西,也需要程式設計師擁有很高的水準,但是如果要成為好的程式設計師就一定要懂多執行緒,我們接下來以幾個問題入手,再進行說明:

如果一個系統專門用於時鐘處理、觸發器處理,這個系統可能是分散式的,那麼在一個系統內部應該如何編寫呢?另外多執行緒中編寫的過程中我們最鬱悶的事情、也是最難琢磨補丁的是什麼:多執行緒現在的執行狀況是怎樣的?我的這個執行緒不能死掉,如果死掉了我怎麼發現?發現到瞭如何處理(自動、人工、難道重啟)?

帶著這些問題,我們引出了文章下面的一些話題。

2、多執行緒應該注意些什麼?

多執行緒用起來爽,出現問題你就不是那麼爽了,簡單說來,多執行緒你最納悶的就是它的問題;但是不要害怕它,你害怕它就永遠不能征服它,呵呵,只要摸清楚一些脾氣,我們總有辦法征服它的。

◆明白多執行緒有狀態資訊,和之間的轉換規則?

◆多執行緒一般在什麼情況下會出現焊住或者死掉的現象?

◆多執行緒焊住或者死掉如何捕獲和處理?

這裡僅僅是提出問題,提出問題後,在說到問題之前,先提及一下擴充套件知識點,下面的章節來說明這些問題。

下載這個文件,這個文件也講述了大部分該框架的使用方法,不過由於該框架本身的封裝層次較多,所以很多底層的實現內容並不是那麼明顯,而且對於執行緒池的管理基本是透明的,自己只能通過一些其他的手段得到這些內容。

所以拿到這個框架首先學習好它的特性後,進一步就是看如何進一步封裝它得到最適合你專案的內容。

另外多執行緒在資料結構選項上也有很多技巧,關於多執行緒併發資源共享上的資料結構選型專門來和大家探討,因為技巧的確很多,尤其是jdk 1.6以後提出了很多的資料結構,它參考了類似於oracle的版本號原理,在記憶體中做了資料複製以及原子拷貝的方法,實現了即保證一致性讀寫又在很大程度上降低了併發的徵用;另外還有對於樂觀鎖機制,也是高效能的多執行緒設計中非常重要知識體系。

3、狀態轉換控制,如何解決死鎖。

 3.1.java預設執行緒的狀態有哪些?(所謂預設執行緒就是自己沒有重寫)

NEW:剛剛建立的執行緒,什麼也沒有做,也就是還沒有使用start命令啟動的執行緒。

BLOCKED:阻塞或者叫梗阻,也就是執行緒此時由於鎖或者某些網路原因造成阻塞,有焊住的跡象。

WAITING:等待鎖狀態,它在等待對一個資源的notify,即資源的一個鎖機會,這個狀態一般和一個靜態資源繫結,並在使用中有synchronzed關鍵字的包裝,當使用obj.wait()方法時,當前執行緒就會等待obj物件上的一個notify方法,這個物件可能是this,如果是this的話那麼在方法體上面一般就會有一個synchronized關鍵字。

TIME_WAITDE:基於時間的等待,當執行緒使用了sleep命令後,就會處於時間等待狀態,時間到的時候,恢復到running狀態。

RUNNING:執行狀態,即執行緒正在處於執行之中(當執行緒被梗阻)。

TERMINATED:執行緒已經完成,此時執行緒的isAlive()返回為false

一般預設的執行緒狀態就是這些,部分容器或者框架會把執行緒的狀態等進行進一步的封裝操作,執行緒的名稱和狀態的內容會有很多的變化,不過只要找好對應的原理也不會脫離於這個本質。

 3.1.執行緒一般在什麼情況下會死掉?

,相互交叉派對,最終導致死鎖;可能是程式中自己導致,編寫共享快取以及自定義的一部分脫離於容器的執行緒池管理這裡就需要注意了;還有就是有可能是分散式的一些共享檔案或者分散式資料庫的鎖導致。

網路梗阻,網路不怕沒有,也不怕太快,就怕時快時慢,現在的話叫太不給力了,傷不起啊!而國內現在往往還就是這樣不給力;當去網路通訊呼叫內容的時候(包括資料庫互動一般也是通過網路的),就很容易產生焊住的現象,也就是假死,此時很難判定執行緒到底是怎麼了,除非有提前的監控預案。

其他情況下執行緒還會死掉嗎?就我個人的經驗來說還沒遇到過,但並非絕不可能,我想在常規的同一個JVM內部操作的執行緒會死掉的概率只有系統掛掉,不然SUNjava虛擬機器也太不讓人信任了;至少從這一點上我們可以決定在絕大部分情況下執行緒阻塞的主要原因是上述兩個主要來源。

在明白絕大部分原因的基礎上,這裡已經提出了問題並初步分析了問題,那麼繼續來如何解決這些問題,或者說將問題的概率降低到非常低的程度(因為沒有百分百的高可用性環境,我們只是要儘量去做到它儘量完美,亞馬遜的雲端計算也有宕機的驚人時刻,呵呵)。

 3.1.多執行緒焊住或者死掉如何捕獲和處理?

說到捕獲,學習java朋友肯定第一想到的是try catch,但是執行緒假死根本不會拋異常,如何知道執行緒死掉了呢?

這需要從我們的設計層面下手,對於後來java提供的執行緒池也可以比較放心的使用,但是對於很多非常複雜的執行緒管理,需要我們自己來設計管理。如何捕獲我們用一個生活中的例子來舉例,下一長中將它反饋到實際的系統設計上。

首先多執行緒自己死掉了它肯定不知道,就想一個人自己喝醉了或者被被人打暈了一樣,呵呵,那麼如何才能知道它的現狀了?提出兩種現實思路,一個是有一個跟班的人,而另一種是它上面有一個領導帶一群人出來玩,下面人丟了一個它肯定要去找。

先看看第一種思路,跟班那個我假如他平時什麼也不做,就跟在前者後面,當發現前者倒下,自己馬上跟上去頂替工作,這也是系統架構上經常採用的冗餘主從切換,可能一主多從;而云計算也是在基礎上的進一步做的異地分流切換和資源動態排程(也就是事情少了,這些人可以去做其他的事情或者睡覺養精神並且為國家節約糧食,當這邊的事情忙不過來,會有做其它事情的人或者待命的人來幫著做這些事情;甚至於此地遭到地震洪水類天災什麼的,異地還有機構可以頂替同樣的工作內容,這樣讓對外的服務永遠不斷間斷下來,也就是傳說中的24*7的高可用性服務),但是這樣冗餘太大,成本將會非常巨大。

再看看第二種服務,上面有一個老大,它過一小會看看這幫小弟在做什麼,是不是遇到了困難,那裡忙它在上面動態調配這資源;好像這種模式很好呢?小弟要是多了,它就忙不過來了,因為資源的分配是需要提前明白下面資源的細節的,不然這個領導不是好領導;那麼再細想下去,我們可以用多個老大,每個老大帶領一個小團隊,團隊之間可以資源調配,但是團隊內部可以由老大自己掌控一切,老大的上面還有個老總它只關心於老大再做什麼,而不需要關心小弟們的行為,這樣大家的事情就平均起來了;那麼問題了又出來了,小弟的問題是可以透明的看到了,要是那個老大出事了甚至於老總出事了怎麼辦?此時結合第一種思想,我們此時就只需要再老總下面掛一個跟班的,集合兩種模式的特徵,也就是小弟不需要配跟班的,這樣就節約了很大的成本(因為葉子節點的數量是最多的),而上面的節點我們需要有跟班的,如果想最大程度節約成本,只需要讓主節點配置一個或者多個跟班就可以,但是這樣恢復成本就上去了,因為恢復資訊需要逐層找到內容才行,一般我們沒有必要在這個基礎上再進一步去節約成本。

這些是現實的東西,如何結合到計算機系統架構中,再回到本文的多執行緒設計上,第四章中一起來探討一下。

4、如何設計一個具有可擴充套件性的多執行緒處理器。

其實在第三章中,已經從生活的管理模式上找到了很多的解決方案,這也是我個人在解決問題上慣用的手段,因為個人認為再複雜的數學演算法也沒有人性本身的複雜,生活中的種種手段若用於計算機中可能會得到很多神奇的效果。

如果自己不使用任何開源技術,要做一個多執行緒處理的框架應該從何下手,在上面分析的基礎上,我們一般會將一個專門處理多執行緒的系統至少分解為主次二層,也就是主執行緒引導多個執行執行緒去處理問題;好了,此時我們需要解決以下幾個問題:

a)多個執行緒處理的內容是類似的,如何控制併發徵用資料或者說降低併發熱點的粒度。

方法1hash雜湊思想將會是優秀的原則,按照資料特徵進行分解資料框,每個框的資料規則按照一種hash規則分佈,hash雜湊對於程式設計容易遍歷,而且計算速度非常迅速,幾乎可以忽略掉定位分組的時間,但結構擴充套件過程比較麻煩,但在多執行緒設計中一般不需要考慮這個問題。

方法2range分佈,range圍分佈資料是提前讓管理者知道資料的大致分佈情況,並按照一種較為平均的規則交給下面的運作執行緒去去處理自己範圍內的資料,相互之間的資料也是沒有任何交叉的,其擴充套件性較好,可以任意擴充套件,如果分解的數量不受控制的話,分解過多,會造成定位範圍比較慢一點,但是多執行緒設計中也一般不用考慮這個問題,因為程式是由自己編寫的。

方法3:點陣圖分佈,即資料具有點陣圖規則,一般是狀態,這種資料按照點陣圖分佈後,執行緒可以設立為點陣圖個數,找到自己的點陣圖段資料即可做操作,而不需要做進一步的更新,但是往往點陣圖數量有限,而需要處理的資料量很大,一個執行緒處理一個位圖下的所有資料也往往力不從心,若多個執行緒處理一個位圖又會重蹈覆轍。

三種方法各自有優缺點,所以我們往往採用組合模式來講真個系統的架構達到比較完美的狀態,當然沒有完美的東西,只有最適應於當前應用環境的架構,所以設計前需要考慮很多預見性問題;關於這種資料分佈更多的用於架構,但是架構的基礎也來源於程式設計思想,兩者思想都是一致的,有關架構和資料儲存分佈,後面有機會單獨討論。

b)執行緒死掉如何發現(以及處理):

管理執行緒除有執行動作的執行緒外,還有1~N跟班,個數根據實際情況決定,至少要有一個當管理執行緒掛掉可以馬上頂替工作,另外還有應當有一個線兩程去定期檢測執行緒的執行情況,由於它只負責這件事情,所以很簡單,而且這一組中的執行緒誰死掉都可以相互替換工作並重啟新的執行緒去替代,這個檢測的週期不用太快、也不用太慢,只要應用可以接受就可以,因為掛掉些東西,應用阻塞一點時間是非常正常的事情。

發現執行緒有阻塞現象,在執行中找到了某種以外而阻塞,導致的原因我們上面已經分析過,解決的方法一般是在探測幾次(這個次數一般是基於配置的)後發現都是處於阻塞狀態,就基本可以認為它是錯誤的了;錯誤的情況此時需要給該執行緒執行一個interrupt()方法,此時執行緒內部的執行會自動的丟擲一個異常,也就是理解執行執行緒的內容的時候尤其是帶有網路操作的時候需要帶上一個try catch,執行部分都在try中,當出現假死等現狀的時候,外部探測到使用一個interrupt()方法,執行程式就會跳轉到catch之中,這個裡面就不存在徵用資源的問題,而快速的將自己的需要回滾的內容執行完,並認為執行緒執行結束,相應的資源也會得到釋放,而使用stop方法之所以現在不推薦是因為它不會釋放資源,會導致很多的問題。

另外寫程式碼之前如果涉及到一些網路操作,一定要對你所使用的網路互動程式有很多的深入認識,如socket互動時,一般情況下如果對方由於網路原因(一般是有IP當時埠不對或者網段的協議不通)導致在啟動連線對方時,socket連線對方好幾分鐘後才會顯示是超時連線,這是預設的,所以你需要提前設定一個啟動連線超時保證網路是可以通訊的,再進行執行(注意socket裡面還有一個超時是連線後不斷的時間,前者為連線之前設定的一個啟動連線超時時間,一般這個時間很短,一般是2秒就很長了,因為2秒都連線不上這個網路就基本連線不上了,而後者是執行,有些互動可能長達幾小時也有可能,但類似這種互動建議採用非同步互動,以保證穩定執行)。

C)如果啟動和管理二級管理執行緒組:

上面有一個主執行緒來控制啟動和關閉,這裡可以將這些執行緒在start前的setDaemon(true),那麼該執行緒將會被設立為後臺執行緒,所謂後臺執行緒就是當主執行緒執行完畢釋放資源後,被主執行緒建立的這些執行緒將會自動釋放資源並死掉,如果一個執行緒被設定為後臺執行緒,若在其run方法內部建立的其他子執行緒,將會自動被建立為後臺執行緒(如果在構造方法中建立則不是這樣)。

管理執行緒也可以像二級執行緒一樣來管理子節點,只要你的程式不怕寫得夠複雜,雖然需要使用非常好的程式碼來編寫,並且需要通過很複雜的測試才會穩定執行,但是一旦成功,這個框架將會是非常漂亮和穩定,而且也是高可用的。

5、多執行緒在多主機下的擴充套件-叢集

其實我們在上面以及提及了一些分散式的知識,也可以叫做資料的分割槽知識(在網路環境利用PC實現類似於同一個主機上的分割槽模式,基本就可以稱為資料是分散式儲存的)。

但是這裡提到的叢集和這個有一些區別,可以說分散式中包含了叢集的概念,但是一般叢集的概念也有很多的區別,並且要分app叢集和資料庫叢集。

叢集一般是指同一個機組下多個節點(同一臺機器也可以部署多個節點),這些節點幾乎去完成同樣的事情,或者說類似的事情,這就和多執行緒扯在一起了,多執行緒也正是如此,對比來看就是多執行緒排程在多主機群組下的實現,所以參照app叢集來說,一般有一個管理節點,它幾乎幹很少的事情,因為我們不想讓它掛掉,因為他雖然乾的事情少,但是卻非常重要,一個是從它那裡可以得到每一個節點的一些應用部署和配置,以及狀態等等資訊;另外是代理節點或者叫做分發節點,它幾乎在管理節點的控制之下只做分發的,當然要保證session一致性。

叢集在多執行緒中的另一個體現就是掛掉一臺,其餘的可以頂替,而不會導致全盤死掉;而叢集組相當於一個大的執行緒組,相關牽制管理,也相互可以失敗切換,而多個業務會或者多種工具項會劃分為不同的叢集組,這就類似於我們設計執行緒中的三層執行緒模式的中多組執行緒組的模式,每組執行緒組內部都有自己個性化的屬性和共享屬性。

而面對資料庫叢集,就相對比app叢集要複雜,app在垂直擴充套件時幾乎只會受到分發節點能力的限制,而這部分是可以調整的,所以它在垂直擴充套件的過程中非常方便,而資料庫叢集則不一樣,它必須保證事務一致性,並實現事務級別切換和一定程度上的網格計算能力,中間比較複雜的也在記憶體這塊,因為它的資料讀入到記憶體中要將多個主機的記憶體配置得像一個記憶體一樣(通過心跳完成),而且需要得到動態擴充套件的能力,這也是資料庫叢集下擴充套件性收到限制發展的一個原因之一。

App難道沒有和資料庫一樣的困難嗎?有,但是粒度相對較小,app叢集一般不需要考慮事務,因為一個使用者的session一般在不出現宕機的情況下,是不會出現複製要求的,而是一直會訪問指定的一臺機器,所以它們之間幾乎不需要通訊;而耦合的粒度在於應用本身的設計,有部分應用系統會自己寫程式碼將一些內容初始化注入到記憶體中,或者注入到app本地的一個檔案中作為檔案快取;這樣當這些資料發生改變時他們先改資料庫,再修改記憶體或者通知記憶體失效;資料庫由於叢集使用心跳連線,所以保持一致性,而app這邊的資料由於只修改掉了自身的記憶體相關資訊,沒有修改掉其他機器的記憶體資訊,所以必然導致訪問其他資料的機器上的內容是不一致的;至於這部分的解決方案,根據實際專案而定,有通過通訊完成的,也有通過共享緩衝區完成(但這種方式又回到共享池資源徵用產生的鎖了),也有通過其他方式完成。

大型系統架構最終資料分佈,集中式管理,分散式儲存計算,業務級別橫向切割,同業務下app垂直分隔,資料級別雜湊+range+點陣圖分佈結構,異地分流容災,待命機組和資源調配的整合,這一切的基礎都來源於多執行緒的設計思想架構在分散式機組上的實現。

6WEB應用的多執行緒以及長連線原理

WEB應用中會對一些特殊的業務服務做特殊的伺服器定製,類似一些高併發訪問系統甚至於專門用於瞬間高併發的系統(很多時候系統不怕高併發,而是怕瞬間高併發)但他們的訪問往往比較簡單,主要用於事務的處理以及資料的一致性保障,他們在資料的處理上要求在資料庫端也不允許有太大的計算量,計算一般在app中去完成,資料庫一般只是做存、取、事務一致性動作,這類一般屬於特殊的OLTP系統;還有大分類一類是屬於併發量不算太大,但每次處理的資料和計算往往比較多,一把說的是OLAP類的系統,而資料的來源一般是OLTPOLAP每次處理的資料量可能會非常大,一般在型別收集和統計上進行資料dump,需要將OLTP中的資料按照某種業務規則方面查詢和檢索的方法提取出來組織為有效資訊儲存在另一個地方,這個地方有可能還是資料庫,但也有可能不是(資料庫的計算能力雖然是資料上最強的但是它在實際應用中它是最慢的一種東西,因為資料庫更多的是需要保證很多事務一致性和鎖機制問題,以及一些中間解析和優化等等產生的開銷是非常大的,而且應用程式與之互動過程是需要通過網路完成,所以很多資料在實際的應用中並不一定非要用資料庫);這兩類系統在設計和架構上都有很大的區別,但普通系統兩者都有特徵,但是都不是那麼極端,所以不用考慮太多,這裡需要提到的是一類非常特殊的系統,是實時性推送資料並高併發的系統,到目前為止我個人不知道將它歸併到哪一類系統中,這的確很特殊的一類系統。

這類系統如:高併發訪問中,而且需要將同一個平臺下的資料讓客戶端較為實時的得到內容,這類網站不太可能一次獲取非常多的內容到客戶端再訪問,而肯定是通過很多非同步互動過程來完成的,下面簡單說下這個非同步互動。

Web非同步互動的所有框架基礎都是ajax,其餘的類似框架都是在這個基礎上完成的;那麼此時ajax應該如何來控制互動才能得到幾乎接近於實時的內容呢?難道通過客戶端不斷去重新整理相同的URL?那要是客戶端非常多,類似於一個大型網站,可能伺服器端很快會宕機,除非用比正常情況高出很多倍的伺服器成本去做,而且更多的伺服器可能在架構上也需要改造才能發揮出他們的效能(因為在伺服器的架構上,1 + 1永遠是小於2的效能,更多的伺服器在開銷)。

想到的另一種辦法就是從伺服器端向客戶端推送資料,那麼問題是如何推送,這類操作是基於一種長連線機制完成,長連線即不斷開的連線,客戶端採用ajax與後端通訊時,後端的反饋資訊只要未曾斷開就可視為一種長連線的機制;很多是通過socket與伺服器端通訊,也可以使用ajax,不過ajax需要在其上面做很多的處理才行。

伺服器端也是必須使用對應的策略,現在較多的是javaNIO,相對BIO效能要低一點,但是也是很不錯的,它在獲取到使用者請求時並不是馬上為使用者請求分配執行緒去處理,而是將請求進行排隊,而排隊的過程可以自己去控制粒度,而執行緒也將作為執行緒池的佇列進行分配處理,也就是伺服器端對客戶端的請求是非同步響應(注意這裡不是ajax單純的非同步互動,而是伺服器端對請求的非同步響應),它對很多請求的響應並非及時,當發生資料變化時,伺服器第一時間通過請求列表獲取到客戶端session列表並與之輸出內容,類似於伺服器端主動推送資料向客戶端;而非同步互動的好處是伺服器端並不會為每一個客戶端分配或新申請一個執行緒,這樣會導致高併發時引起的資源分配不過來導致的記憶體溢位現象;解決了上述兩個問題後,另外還有一個問題需要解決的是,當一個執行緒在處理一個請求任務時,由於執行緒處理一個任務完成前除非死掉或者焊住,否則是不會斷開下來的,這個是肯定的(我們可以將一些大任務切割為一些小任務,執行緒就處理的速度就會快很多了),但是有一個問題是,伺服器端的這個執行緒可能很快處理好了需要處理的資料內容並向客戶端推送,但是客戶端由於各類網路通訊問題,導致遲遲不能接受完成,此時該執行緒也會被佔用些不必要的時間,那麼是否在這個中間需要進一步做一層斷點傳送的快取呢?快取不僅僅是屬於在斷點資料需要時取代應用伺服器的內容,非同步斷點向客戶端輸出資訊,同時將應用伺服器處理的時間幾乎全部集中在資料和業務處理,而不是輸出網路上的很多佔用,有關網路快取有很多種做法,後續有機會和大家一起探討關於網路快取的知識吧。