java併發編程的藝術讀書筆記(一)

併發編程的目的是爲了程序運行的更快。java

1.上下文切換:算法

時間片:cpu分配給各個線程的時間。數據庫

單核處理器也支持多線程執行代碼。編程

cpu經過時間片分配算法來循環執行任務,任務從保存到再加載的過程就是一次上下文切換。多線程

多線程不必定快,由於線程有建立和上下文切換的開銷。併發

使用Lmbench能夠測試上下文切換的時長(何時須要看這個參數呢)。socket

使用vmstat能夠測量上下文切換的次數。好比:執行vmstat 1,再看cs的值,cs表示上下文切換的次數,這個值表示每一秒鐘上下文切換的次數。(何時須要用到這個命令呢?)測試

減小上下文切換的方法:優化

1.無鎖併發編程。多線程競爭鎖時,會引起上下文切換,因此多線程處理數據時,能夠用一些辦法來避免使用鎖,好比將數據的ID按照Hash算法取模分段,不一樣的線程處理不一樣段的數據。atom

2.CAS算法。eg:java的atomic包使用CAS算法來更新數據,而不須要加鎖。

3.使用最少線程。

4.使用協程。協程:在單線程裏實現多線程的調度,並在單線程裏維持多個線程間的切換。

減小上下文切換實戰:

經過減小線上大量WAITING的線程,來減小上下文切換的次數。

第一步:用jstack命令dump線程信息,看pid爲3117的進程在作什麼

sudo -u admin jstack 3117>/temp

第2步:統計全部線程分別處於什麼狀態

grep java.lang.Thread.State temp | awk '{print $2$3$4$5}'   | sort | uniq -c

原本應該截圖的,不太方便直接把命令和結果賦值粘貼過來:

[tengfei.fangtf@ifeve ~]$ grep java.lang.Thread.State dump17 | awk '{print $2$3$4$5}'
    | sort | uniq -c
39 RUNNABLE
21 TIMED_WAITING(onobjectmonitor)
6 TIMED_WAITING(parking)
51 TIMED_WAITING(sleeping)
305 WAITING(onobjectmonitor)
3 WAITING(parking)

第三步:打開dump文件查看處於WAITING(onobjectmonitor)的線程在作什麼,好比這本書的例子中,基本都是JBOSS的工做線程在await,說明JBOSS線程池裏線程池裏接受的任務太少;減小JBOSS的工做線程數,找到JBOSS的線程池配置信息,將maxThreads值調小。重啓JBOSS,再dump線程信息,而後統計WAITING(onobjectmonitor)的線程,發現減小了不少。=====》由於每一次從WAITING到RUNNABLE都會進行一次上下文的切換。

=====》拓展:

什麼使用須要用到jstack命令dump線程信息?

我印象很深的一次就是一個lisener的項目,上線一段時間後,某個隊列忽然都阻塞了,消息不消費了,當時在listener admin控制檯把阻塞的線程停用再啓用,阻塞的消息很快都消費了,過了一段時間,這個項目的對應的另外一個隊列阻塞,停用再啓用以後阻塞的消息也都消費了,可是有一條unacked,當時用jstack命令dump了線程信息,而後在本地啓動項目,在dump線程信息,異常的線程信息和正常的線程信息對比,排查問題。====》這個是由於esl鏈接有問題,是怎麼發現是esl的鏈接有問題的。想不起來了,這個記得本身研究下,作一下記錄。

死鎖的時候須要用這個命令dump線程信息。

2.死鎖

一旦出現死鎖,業務是能夠感知的,由於不能繼續提供服務了,只能經過dump線程查看究竟是哪一個線程出現了問題。

===》工做中是否遇到過線上環境死鎖?我聽過同事遇到過,向他請教下他是怎麼知道的,怎麼排查的,怎麼解決問題的,作好筆記。

避免死鎖的方法:

1.避免一個線程同時獲取多個鎖。

2.避免一個線程在鎖內同時佔用多個資源,儘可能保證每一個鎖只佔用一個資源。

3.嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內部鎖機制。====》sornarlint優化的時候,遇到一個鎖的優化,後來由於優化會有潛在風險,沒有優化,看看那個點,對比總結下。

4.對於數據庫鎖,加鎖和解鎖必須在一個數據庫鏈接裏,不然會出現解鎖失敗的狀況。

3.資源限制的挑戰

資源限制:在進行併發編程時,程序的執行速度受限於計算機硬件資源或軟件資源。

硬件資源限制有帶寬的上傳/下載速度、硬盤讀寫速度和CPU的處理速度。

軟件資源限制有數據庫的鏈接數和socket鏈接數等。

資源限制引起的問題:併發執行的代碼受資源限制串行執行,速度會更慢,增長了上下文切換和資源調度的時間。

若是解決資源限制的問題:對於硬件資源限制,能夠考慮使用集羣並行執行程序。對於軟件資源限制,能夠考慮使用資源池將資源複用。總之,根據不一樣的資源限制調整程序的併發數。

java併發機制的底層實現原理:

java代碼在編譯後會變成java字節碼,字節碼被類加載器加載到JVM裏,JVM執行字節碼,最終須要轉化爲彙編指令在CPU上執行,java中所使用的併發機制依賴於JVM的實現和CPU的指令。 1.volatile volatile是輕量級的synchronized,它在多處理開發中保證了共享變量的「可見性」。 volatile使用恰當的話,比synchronized使用和執行成本更低,它不會引發線程上下文的切換和調度。

先了解幾個CPU術語:

未完待續。。。。

相關文章
相關標籤/搜索