1. 程式人生 > 其它 >多執行緒與訊息佇列

多執行緒與訊息佇列

多執行緒

  • 通常多執行緒的應用不是為了提高執行效率,而是為了提高資源使用效率。
  • 多執行緒程式設計的目的,就是"最大限度地利用CPU資源",在某種程度上可以看成是給一個應用程式增加了多工功能。
  • 即採用多執行緒不會提高程式的執行速度,反而會降低速度,但是對於使用者來說,可以減少使用者的響應時間。
  • 對於多CPU或者CPU採用超執行緒技術的話,採用多執行緒技術還是會提高程式的執行速度的。

建立執行緒池的5種方式

  • 執行緒池(ThreadPool)是一種基於池化思想管理和使用執行緒的機制。它是將多個執行緒預先儲存在一個“池子”內,當有任務出現時可以避免重新建立和銷燬執行緒所帶來效能開銷,只需要從“池子”內取出相應的執行緒執行對應的任務即可。
  • 一、通過Executors類提供的4種方法:
    1. newCachedThreadPool(建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。)
    2. newFixedThreadPool(建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。)
    3. newScheduledThreadPool(建立一個定長執行緒池,支援定時及週期性任務執行。)
    4. newSingleThreadExecutor(建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。)
  • 二、通過ThreadPoolExecutor類自定義:
    5. ThreadPoolExecutor類提供了4種構造方法,可根據需要來自定義一個執行緒池。

ThreadPoolExecutor執行緒池的內部工作原理及相關引數

主要引數為:核心執行緒數、阻塞佇列、最大執行緒數、拒絕策略。

訊息佇列

  • 訊息(Message)是指應用於應用之間傳送的資料,訊息的型別包括文字字串、JSON、XML、內嵌物件等等...
  • 所謂 訊息中介軟體 / 訊息佇列(Message Queue Middleware,簡稱MQ)是利用高效可靠的訊息傳遞機制進行資料交流,同時可以基於資料通訊來進行分散式系統的繼承,訊息中介軟體一般有兩種傳遞模式:點對點(Point-to-Point)模式和釋出/訂閱(Pub/Sub)模式,點對點模式是基於佇列的,訊息生產者傳送訊息到佇列,訊息消費者從佇列中接收訊息,佇列的存在使得訊息的非同步傳輸成為了可能,釋出訂閱模式定義瞭如何向一個內容節點發布和訂閱內容,這個內容節點叫topic,這種模式可以滿足消費者釋出一個訊息,多個消費者同時消費同一資訊的需求。
  • 一般來說,訊息佇列是一種非同步的服務間通訊方式,是分散式系統中重要的元件,主要解決應用耦合,非同步訊息,流量削鋒等問題,實現高效能,高可用,可伸縮和最終一致性架構。使用較多的訊息佇列有ActiveMQ、RocketMQ、RabbitMQ、Kafka等。

多執行緒和訊息佇列的區別?

  • 多執行緒是防止系統的阻塞(優先響應使用者,後臺任務執行)
  • 訊息佇列是提高系統處理業務的效率(非同步處理加快程式執行速度)

訊息佇列和多執行緒的選擇

  1. 可靠性要求高時選擇訊息佇列:訊息佇列和多執行緒兩者並不衝突,多執行緒可以作為佇列的生產者和消費者。使用外部的訊息佇列時,第一是可以提高應用的穩定性,當程式fail後,已經寫入外部訊息佇列的資料依舊是儲存的,如果使用兩步commit的佇列的話,可以更加提高這個專案。
  2. 不著急知道結果,儘量使用訊息佇列,保證伺服器的壓力減小,因為多執行緒對cpu的消耗大一點:用執行緒的話,會佔用主伺服器資源, 訊息佇列的話, 可以放到其他機器上執行, 讓主伺服器儘量多的服務其他請求。我個人認為, 如果使用者不急著知道結果的操作, 用訊息佇列, 否則再考慮用不用執行緒。
  3. 需要解耦的時候用訊息佇列:解耦更充分,架構更合理。多執行緒是在程式語言層面解決問題,訊息佇列是在架構層面解決問題。我認為架構層面解決問題是“覺悟比較高的方式“,理想情況下應該限制語言層面濫用多執行緒,能不用就不用。
  4. 如果容易出現執行緒安全問題的業務或者批量操作時,也儘量使用訊息佇列:批量傳送郵件時,資料量龐大,如果使用多執行緒對系統不安全。

訊息佇列和執行緒池的比較

  1. 兩者內部都使用了佇列,如阻塞佇列、優先順序佇列;
  2. 使用執行緒池時應用伺服器既充當生產者又充當消費者,也是訊息佇列中介軟體的實現者,使用訊息佇列時中介軟體、生產者、消費者可以部署在不同的應用機器上(當然也可以部署在一臺伺服器上但很少有人這麼用);
  3. 出於第2點執行緒池更適合非分散式的系統,但在分散式架構下訊息佇列明顯是更突出優勢;
  4. 使用訊息佇列會帶來額外的網路開銷;
  5. 訊息佇列的耦合性更低,可擴充套件性更好,適用於弱一致性的場景,如對log日誌的解耦;
  6. 訊息佇列自動實現訊息的持久化,中間已經實現了大量功能,如訊息轉發、訊息拒絕、訊息重試,以及對訊息的一些監控,例如訊息的消費狀態、訊息的消費速率等,使用執行緒池如果需要很多功能還要自己去實現,例如需要執行狀態需要列印佇列數量、計算訊息消費速度;
  7. 在不同系統間的服務呼叫(呼叫協議也可能不一致)執行緒池很難實現或開銷很大,這時候訊息佇列可以遮蔽不同機器或不同協議的問題;
  8. 使用訊息佇列會提升系統的複雜度,網路抖動怎麼辦?最大佇列長度怎麼設定?超時時間又設定多少?Qos又設定為多少?消費者多少個比較合適?Channel cache size又該設定為多少?業務線可能都是用同一個Mq,你佔資源太多,或者設計不當可能會導致整個Mq故障。