Java項目性能瓶頸分析及定位(八)——Java線程堆棧分析(五)


對於CPU而言,常見的瓶頸主要有兩種:
服務器的壓力很小,但是CPU的利用率卻很高,這樣的性能瓶頸相對比較容易定位(好比我只是說了你一句,你就哭了,你的弱點立馬就暴露出來了);
給服務器施加的壓力很大,但是CPU的利用率總是很低,也就是壓力上不去,這類瓶頸最常見,定位起來也最困難(類似我對你用盡了各種手段,你就是不說實話,內心太強大了)。
影響壓力上不去的因素很多,但是對於性能測試工程師而言,最具價值的瓶頸肯定是由於代碼問題引起的了(定位到是代碼問題導致的壓力上不去,特有成就感),而導致這類問題出現的最常見的一個知識點,肯定就是鎖了,如果對於Java多線程的鎖機制不甚了解,分析定位代碼的瓶頸和性能調優幾乎是不可能的。
鎖——確保多線程訪問的數據一致性。
目前Java多線程的鎖基本就是通過如下兩種方式實現:
synchronized關鍵字
java.util.concurrent.locks包下的類(用的也蠻多,稍微有點復雜,課堂上講吧)
今天就為大家分享synchronized關鍵字實現的加鎖方式。
認識synchronized
假設這樣一個場景,張三和李四都需要維修各自的電腦,但是只有一把螺絲刀工具,意味着同一時刻只能有一個人使用這把工具修他們的電腦,那么使用Java代碼該如何實現呢?我們把張三和李四比喻成兩個線程,把他們修電腦的過程用Java語言實現一下,開始!

上面代碼執行后對線程做dump,摘取部分信息如下:

解讀鎖
wait()和sleep()
它們有一個共同點是,都會把當前的線程阻塞住( 時長為函數參數指定的時間), 我們稱之為睡眠或者等待。但二者實際上是完全不同的兩個函數, 二者有着最為本質的區別:
wait()  當線程執行到wait()方法上, 當前線程會釋放監視鎖, 此時其它線程可以占有該鎖,一旦wait()方法執行完成, 當前線程又繼續嘗試獲取該鎖, 直到執行完該鎖的作用域。 可以說wait()是多線程場合下用得最多的一個方法。 結合notify(),可以實現兩個線程之間的通信,一個線程可以通過這種方法通知另一個線程繼續執行, 完成線程之間的配合。 wait()和鎖的示意圖如下:

在wait(5000)這5秒( 5000毫秒) 期間, 當前線程會釋放它占有的鎖, 此時其它線程有機會獲得該鎖。 當wait(5000)執行完成后, 當前線程繼續獲得該鎖的使用權。 滿足如下條件之一, wait()方法退出:
達到了等待的時間之后, 自動退出。 如wait(5000),5秒后wait方法退出。
其它的線程調用了該鎖的notify()方法。 如果多個線程在等待同一個鎖, 只有一個線程會被通知到。
sleep()  與鎖操作無關, 如果該方法恰好在一個鎖的保護范圍之內, 當前線程即使在執行sleep()的時候, 仍然繼續保持監視鎖。 該方法實際上僅僅是完成等待或者睡眠的語義。 示意圖如下:

從上面的代碼Thread.sleep(5000)可以看出, sleep()方法並不是鎖上面的一個方法, 而是線程的一個靜態方法。 也就是說該方法實際上是和鎖操作無關的。 如果sleep()方法恰好在一個鎖的保護范圍之內, 那么當前線程即使執行到該sleep方法, 也不會產生特別的鎖操作(持有鎖或者釋放鎖), 如果原來持有, 現在仍然持有。 如果原來沒有持有, 那么現在仍然不持有。
還記得第六篇文章解讀的線程堆棧嗎?包含的直接信息有:
線程的個數、 每個線程調用的方法堆棧、 當前鎖的狀態。 線程的個數可以直接數出來; 線程調用的方法堆棧, 從下向上看,即表示當前的線程調用了哪個類上的哪個方法。 而鎖的狀態看起來稍微有一點技巧。 與鎖相關的三個重要信息如下:
當一個線程占有一個鎖的時候, 線程堆棧中會打印—locked <0x24a23208>
當一個線程正在等待其它線程釋放該鎖, 線程堆棧中會打印—waiting to lock <0x24a23208>
當一個線程占有一個鎖, 但又執行到該鎖的wait()上, 線程堆棧中首先打印locked,然后又會打印—waiting on <0x24a23208>
源碼:




運行上面的程序,打印堆棧信息如下:



從上面這個例子中, 可以很清晰地看出, 在線程堆棧中與鎖相關的三個最重要的特征字:locked,waiting to lock,waiting on;了解這三個特征字, 就能夠對鎖進行分析了。
一般情況下, 當一個(些)線程在等待一個鎖時, 應該有一個線程占用這個鎖, 即如果有的線程在等待一個鎖, 該鎖必然被另一個線程占有了, 也就是說, 從打印的堆棧中如果能看到waiting to lock <0x04d02238>,應該也應該能找到一個線程locked <0x04d02238>。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM