标題 Spring MVC 基于阻塞隊列 LinkedBlockingQueue 的同步長輪詢功能實作,其實本文介紹的也是生産者消費者的一種實作。生産者不必是一個始終在執行的線程,它可以是一個接口,接受用戶端的請求,向隊列中插入消息;消費者也不必是一個始終在執行的線程,它同樣也可以是一個接口,接受用戶端的請求,從隊列中取出屬于自己的消息;看到很多介紹生産者消息者實作的文章,實作場景都很簡單,現實應用往往會比較複雜,有一些附加條件,本例中就需要根據消息中的 familyId 來判斷消息是不是下發給自己的。
本例的應用場景是一個物聯網智能家居應用,系統結構圖如下:

主要實作的功能是使用者通過手機端APP發出裝置控制的指令(如:開燈、關燈等)後,裝置網關能夠實時的擷取到控制指令,進而控制設定的狀态。
其實可選的方案有很多種:
1、長輪詢
2、長連結
3、Socket
4、WebSocket
5、MQTT
選擇長輪詢方案是因為其實作的簡單性,實作起來與其它的接口基本沒有太大的差别。
同步服務為每個請求建立單一線程,由此線程完成整個請求的處理:接收消息,處理消息,傳回資料;這種情況下伺服器資源對所有入棧請求開放,伺服器資源被所有入棧請求競争使用,如果入棧請求過多就會導緻伺服器資源耗盡當機,或者導緻競争加劇,資源排程頻繁,伺服器資源利用效率降低。
異步服務則可以分别設定兩個線程隊列,一個專門負責接收消息,另一個專門負責處理消息并傳回資料,另有一些值守線程負責任務派發和逾時監控等工作。在這種情況下無論入棧請求有多少,伺服器始終依照自己的能力處理請求,伺服器資源消耗始終在一個可控的範圍。這種模式的一個問題就是這兩個線程隊列的大小如何根據機器負載情況動态調整。
這種情況下,雖然入棧請求以消息隊列的方式被異步處理但每個請求内部卻是采用阻塞的方式通路外部資源,如果外部資源通路速度過慢,可能導緻請求處理隊列中的所有線程均處于阻塞狀态,此時CPU使用率雖然很低但是卻因為隊列中線程已滿而無法處理消息隊列中的新消息,此時若能調整線程隊列最大線程數将可提高CPU使用率。但另一個問題是如果線程數被調高之後所有線程的IO處理突然結束并且接下來每個線程都将進行大量計算的話那麼CPU可能出現過載。
在系統運作的每個時間點上,當時正在進行IO的線程數量和正在進行計算的線程數量是不斷變化着的,那麼如何才能設計出一個可以根據系統當時情況自動适應負載變化的高度自适應的系統呢?
在這方面采用反應式計算模型确實能設計出适應負載能力很強的系統,系統使用率和吞吐量可以大幅提高,但這種系統仍然可能會出現系統局部負載過高的風險。
采用反應式計算模型,不僅系統中的入棧請求以消息隊列的方式得以異步化,而且系統中所有的IO任務也必需依照此法行之,這些IO任務的處理需要采用異步模型(如NIO)。另外要考慮的就是如何劃分異步IO消息并為其配置線程隊列了,比如是要将所有IO任務放入統一的隊列還是為某類IO任務設定單獨的隊列。
伺服器資源雖然由系統配置設定但大多以線程為持有者被線程持有并使用,如線程堆棧,被線程持有的各類鎖等資源。
我這裡是定義的靜态常量,你找個類把它放進去就可以了。
Equipment 是一個消息實體類,在本例中它最關鍵的屬性是 familyId,因為要根據它來判斷消息是下發給哪個家庭的,你發了一個關燈的指令結果我家的燈滅了這肯定是不行的。
生産者不必是一個始終在執行的線程,它可以是一個接口,接受用戶端的請求;
這裡你要做的最關鍵的是:向隊列中插入消息。
Personal 是一個使用者資訊實體類,通過 SecurityUtils.getPersonal(request); 方法根據 Session 或 Cookie 來從緩存或資料庫中擷取目前登入使用者資訊。
此接口由網關調用。
這裡要做的循環從隊列中取資料,然後根據 familyId 判斷消息是不是屬于自己的,是就退出循環,不是就把剛剛取出的消息再放回去。
為什麼要這樣設計呢?
因為如果隻是通過 peek 方法來擷取,而不從 隊列 中移除,如果隊列頭部的消息不是屬于自己的,那就要一直循環下去卻得不到屬于自己的那一條消息。
測試方法通過一個回調函數,不斷的向伺服器送出請求;
如果伺服器隊列中有屬于自己的消息,會立即傳回,沒有就會一直等待真到逾時,然後重新發起請求。
請求成功後會在 Div 中顯示成功的次數,失敗了也會顯示失敗的狀态文本。
可以通過浏覽器的開發者工具中的 Network 來檢視每次請求所用的時間:
本例的實作方式是同步的,隊列沒有設定大小,生産者被阻塞的可能性很小,除非所有網關都與平台斷開了連接配接不再處理消息;但消費者的實作由于是同步的,會對伺服器的性能有所影響,因為每個消費者請求會占用一個 Servlet 線程導緻無法再去處理其它使用者請求。那麼這個問題有沒有解決方案呢?當然有!那就是采用異步處理模式 DeferredResult 。
相關閱讀
隊列
阻塞隊列
同步與異步處理模式分析詳解(圖)
長輪詢與長連結
<a target="_blank" href="http://blog.csdn.net/testcs_dn/article/details/72909676">Bluemix 之雲資料庫 ClearDB 原理與應用實踐</a>