Java並發編程之線程上下文切換

Java併發編程之線程上下文切換

作為一名Java開發者我們心中都有一個概念就是併發是比串行快的,因為併發是多個線程幹活,而串行是一個線程幹活的,那麼這樣想來,併發當時是比串行快的,如果只這樣想就錯了。今天小編給各位看官普及點併發編程的知識。本文主要內容出自《Java併發編程的藝術》一書,是對該書內容的歸納和理解。

多線程一定快嗎?

併發測試代碼

Java併發編程之線程上下文切換

串行測試代碼

Java併發編程之線程上下文切換

測試結果

Java併發編程之線程上下文切換

答案是不一定的哦

從表中可以看出當併發執行累加操作不超過百萬次時,其實併發速度會比串行執行累加操作要慢一點。那麼為什麼併發執行的速度還比串行慢呢?就是我們這篇文章要說的。

測試上下文切換次數和時長

給大家推薦一個統計服務器信息的Linux命令: vmstat命令

vmstat命令的含義為顯示虛擬內存狀態(“Viryual Memor Statics”),但是它可以報告關於進程、內存、I/O等系統整體運行狀態。

語法: vmstat(選項)(參數)

選項:

-a:顯示活動內頁;

-f:顯示啟動後創建的進程總數;

-m:顯示slab信息;

-n:頭信息僅顯示一次;

-s:以表格方式顯示事件計數器和內存狀態;

-d:報告磁盤狀態;

-p:顯示指定的硬盤分區狀態;

-S:輸出信息的單位。

參數:

事件間隔:狀態信息刷新的時間間隔;

次數:顯示報告的次數。

實例(我們統計上面測試代碼的上下文切換信息)

Java併發編程之線程上下文切換

CS(Content Switch)表示上下文切換的次數,從上面的測試結果中,我們可以看到其中上下文的每一秒鐘切換1000多次。

那麼如何減少上下文切換

減少上下文切換的方法有無鎖併發編程、CAS算法、單線程編程和使用協程。

  • 無鎖併發編程。多線程競爭鎖時,會引起上下文切換,所以多線程處理數據時,可以用一些辦法來避免使用鎖,如將數據用ID進行Hash算法後分段,不同的線程處理不同段的數據。
  • CAS算法。Java的Atomic包使用CAS算法來更新數據,而不需要加鎖。
  • 使用最少線程。避免創建不需要的線程,比如任務很少,但是創建了很多線程來處理,這樣會造成大量線程都處於等待狀態。
  • 協程:在單線程裡實現多任務的調度,並在單線程裡維持多個任務間的切換。

併發編程還要注意一個問題: 資源限制

eg:

(1)什麼是資源限制?

資源限制是指在進行併發編程時,程序的執行速度受限於計算機硬件資源或軟件資源的限制。比如服務器的帶寬只有2M,某個資源的下載速度是1M每秒,系統啟動十個線程下載資源,下載速度不會變成10M每秒,所以在進行併發編程時,要考慮到這些資源的限制。硬件資源限制有帶寬的上傳下載速度,硬盤讀寫速度和CPU的處理速度。軟件資源限制有數據庫的連接數和Sorket連接數等。

(2)資源限制引發的問題

併發編程將代碼執行速度加速的原則是將代碼中串行執行的部分變成併發執行,但是如果某段串行的代碼併發執行,但是因為受限於資源的限制,仍然在串行執行,這時候程序不僅不會執行加快,反而會更慢,因為增加了上下文切換和資源調度的時間。例如,之前看到一段程序使用多線程在辦公網併發的下載和處理數據時,導致CPU利用率100%,任務幾個小時都不能運行完成,後來修改成單線程,一個小時就執行完成了。

(3)如何解決資源限制的問題?

對於硬件資源限制,可以考慮使用集群並行執行程序,既然單機的資源有限制,那麼就讓程序在多機上運行,比如使用ODPS,hadoop或者自己搭建服務器集群,不同的機器處理不同的數據,比如將數據ID%機器數,得到一個機器編號,然後由對應編號的機器處理這筆數據。

對於軟件資源限制,可以考慮使用資源池將資源複用,比如使用連接池將數據庫和Sorket連接複用,或者調用對方webservice接口獲取數據時,只建立一個連接。

(4)在資源限制情況下進行併發編程

那麼如何在資源限制的情況下,讓程序執行的更快呢?根據不同的資源限制調整程序的併發度,比如下載文件程序依賴於兩個資源,帶寬和硬盤讀寫速度。有數據庫操作時,要數據庫連接數,如果SQL語句執行非常快,而線程的數量比數據庫連接數大很多,則某些線程會被阻塞住,等待數據庫連接。

Java併發編程之線程上下文切換


分享到:


相關文章: