標籤:swa zed 使用 多個 第一個 所有權 輸送量 就是 被佔用
同步的基本思想
為了保證共用資料在同一時刻只被一個線程使用,我們有一種很簡單的實現思想,就是
在共用資料裡儲存一個鎖 ,當沒有線程訪問時,鎖是空的。
當有第一個線程訪問時,就 在鎖裡儲存這個線程的標識 並允許這個線程訪問共用資料。
在當前線程釋放共用資料之前,如果再有其他線程想要訪問共用資料,就要 等待鎖釋放 。
- 在共用資料裡儲存一個鎖
- 在鎖裡儲存這個線程的標識
- 其他線程訪問已加鎖共用資料要等待鎖釋放
Jvm同步的實現
jvm中有以下三種鎖(由上到下越來越“重量級”):
- 偏向鎖
- 輕量級鎖
- 重量級鎖
重量級鎖
Synchronized 原理
我們直接參考JVM規範中描述:每個對象有一個監視器鎖(monitor)。
當monitor被佔用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試擷取monitor的所有權,過程如下:
1、如果monitor的進入數為0,則該線程進入monitor,然後將進入數設定為1,該線程即為monitor的所有者。
2、如果線程已經佔有該monitor,只是重新進入,則進入monitor的進入數加1.
3.如果其他線程已經佔用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試擷取monitor的所有權。
Synchronized的語義底層是通過一個monitor的對象來完成,其實wait/notify等方法也依賴於monitor對象,
這就是為什麼只有在同步的塊或者方法中才能調用wait/notify等方法,否則會拋出java.lang.IllegalMonitorStateException的異常的原因。
Synchronized是通過對象內部的一個叫做監視器鎖(monitor)來實現的。
但是監視器鎖本質又是依賴於底層的作業系統的互斥鎖(Mutex Lock)來實現的。而作業系統實現線程之間的切換這就需要從使用者態轉換到核心態,這個成本非常高,狀態之間的轉換需要相對比較長的時間,這就是為什麼Synchronized效率低的原因。
因此,這種依賴於作業系統互斥鎖(Mutex Lock)所實現的鎖我們稱之為“重量級鎖”。
輕量級鎖
鎖的狀態總共有四種:無鎖狀態、偏向鎖、輕量級鎖和重量級鎖。
JDK 1.6中預設是開啟偏向鎖和輕量級鎖的,我們也可以通過-XX:-UseBiasedLocking來禁用偏向鎖。
輕量級鎖的核心思想就是“被加鎖的代碼不會發生並發,如果發生並發,那就膨脹成重量級鎖(膨脹指的鎖的重量級上升,一旦升級,就不會降級了)”。
輕量級鎖依賴了一種叫做CAS(compare and swap)的操作。
術語定義
| 術語 |
英文 |
說明 |
| CAS |
Compare and Swap |
比較並設定。 用於在硬體層面上提供原子性操作。 在 Intel 處理器中,比較並交換通過指令cmpxchg實現。比較是否和給定的數值一致,如果一致則修改,不一致則不修改。 |
偏向鎖
根據輕量級鎖的實現,我們知道雖然輕量級鎖不支援“並發”,遇到“並發”就要膨脹為重量級鎖,但是輕量級鎖可以支援多個線程以串列的方式訪問同一個加鎖對象。
比如A線程可以先擷取對象o的輕量鎖,然後A釋放了輕量鎖,這個時候B線程來擷取o的輕量鎖,是可以成功擷取得,以這種方式可以一直串列下去。
之所以能實現這種串列,是因為有一個釋放鎖的動作。那麼假設有一個加鎖的java方法,這個方法在啟動並執行時候其實從始至終只有一個線程在調用,但是每次調用完卻也要釋放鎖,下次調用還要重新獲得鎖。
那麼我們能不能做一個假設:“假設加鎖的代碼從始至終就只有一個線程在調用,如果發現有多於一個線程調用,再膨脹成輕量級鎖也不遲”。這個假設,就是偏向鎖的核心思想。
偏向鎖依賴了一種叫做CAS(compare and swap)的操作。
總結
本文重點介紹了JDk中採用輕量級鎖和偏向鎖等對Synchronized的最佳化,
但是這兩種鎖也不是完全沒缺點的,比如競爭比較激烈的時候,不但無法提升效率,反而會降低效率,因為多了一個鎖定擴大的過程,這個時候就需要通過-XX:-UseBiasedLocking來禁用偏向鎖。下面是這幾種鎖的對比:
鎖 |
優點 |
缺點 |
適用情境 |
偏向鎖 |
加鎖和解鎖不需要額外的消耗,和執行非同步方法比僅存在納秒級的差距。 |
如果線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗。 |
適用於只有一個線程訪問同步塊情境。 |
輕量級鎖 |
競爭的線程不會阻塞,提高了程式的響應速度。 |
如果始終得不到鎖競爭的線程使用自旋會消耗CPU。 |
追求回應時間。 同步塊執行速度非常快。 |
重量級鎖 |
線程競爭不使用自旋,不會消耗CPU。 |
線程阻塞,回應時間緩慢。 |
追求輸送量。 同步塊執行速度較長。 |
參考如下:
51932179
Java並發機制及鎖的實現原理