iis怎么做網(wǎng)站站長工具推薦網(wǎng)站
目錄
- 1. 本地鎖
- 1.1. 悲觀鎖與樂觀鎖
- 1.2. 公平鎖與非公平鎖
- 1.3. CAS
- 1.4. synchronized
- 1.5. volatile 可見性
- 1.6. ReentrantLock 可重入鎖
- 1.7. AQS
- 1.8. ReentrantReadWriteLock 可重入讀寫鎖
- 2. 分布式鎖
- 3. 額外的
- 3.1. synchronized 的鎖升級原理
- 3.2. synchronized鎖原理
1. 本地鎖
1.1. 悲觀鎖與樂觀鎖
是一種思想,按遇到并發(fā)問題概率的思考,分為:樂觀鎖(很少發(fā)生并發(fā)問題)、悲觀鎖(一定會發(fā)生并發(fā)問題)
- 樂觀鎖 的實現(xiàn)有 CAS
- 悲觀鎖 的實現(xiàn)有 synchronized、lock等
1.2. 公平鎖與非公平鎖
按獲取鎖的順序,分為:公平鎖(按順序獲取鎖)、非公平鎖(看誰喚醒快,誰就搶到鎖)
1.3. CAS
CAS 即比較與保存,底層使用的是一種自旋鎖。
CAS存在ABA問題,解決辦法,添加版本標識。
CAS常見的實現(xiàn)類有:
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference 等等。
1.4. synchronized
synchronized 是一種同步鎖,可以鎖方法與鎖代碼塊(鎖對象)。
根據(jù)鎖的并發(fā)程度不同,升級鎖(不可降級),分為三個狀態(tài):偏向鎖
、輕量級鎖
、重量級鎖
。
偏向鎖
- 無多線程下,拿鎖不需要競爭。在對象Mark Word中記錄偏向線程ID。輕量級鎖
- 多線程下,拿不到鎖,就會進入輕量級鎖。使用CAS方式自旋獲取鎖。重量級鎖
- 并發(fā)量大時,就會進入重量級鎖。使用的是互斥鎖。
synchronized方法:就會標識ACC_SYNCHRONIZED,最后由monitor實現(xiàn)
synchronized代碼塊:直接使用了monitorenter 和 monitorexit 指令。
參考文章:
- synchronized的原理
- synchronized原理詳解
1.5. volatile 可見性
volatile 使用了內(nèi)存屏障
,讀的時候使用讀屏障
,寫的時候使用寫屏障
,保證了數(shù)據(jù)都是從主內(nèi)存中獲取。線程不安全
1.6. ReentrantLock 可重入鎖
ReentrantLock繼承于Lock
ReentrantLock 包含公平鎖和非公平鎖,通過構造方法設置,默認是非公平鎖。
常用的方法:
lock
加鎖tryLock
嘗試獲取鎖,分為兩種方式,一種一直等待獲取鎖,一種在有效時間內(nèi)獲取鎖,獲取不了鎖,就返回false。lockInterruptibly
中斷等待獲取鎖的線程unlock
解鎖newCondition
創(chuàng)建條件,等待與喚醒,與線程Thread的await和notify類似。有如下方法:await
等待線程signal
喚醒線程
1.7. AQS
AQS 全稱 AbstractQueuedSynchronizer,為實現(xiàn)依賴于先進先出 (FIFO) 等待隊列的阻塞鎖定和相關同步器(信號量、事件,等等)提供一個框架。
AbstractQueuedSynchronizer
抽象隊列同步器,里面維護了一個FIFO隊列,實現(xiàn)類有:Sync
同步鎖,實現(xiàn)類有:NonfairSync
非公平鎖FairSync
公平鎖
應用于AQS的類有:
CountDownLatch、ReentrantLock、 ReentrantReadWriteLock、 Semaphore、 ThreadPoolExecutor
1.8. ReentrantReadWriteLock 可重入讀寫鎖
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();// 讀鎖
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();// 寫鎖
ReentrantReadWriteLock
讀寫鎖WriteLock
使用了AQS中的獨占鎖
,具有排它性。ReadLock
使用了AQS中的共享鎖
,允許多個線程讀。
讀鎖和寫鎖都會導致線程阻塞。
鎖降級:還允許將寫鎖降級為讀鎖
,方法是先獲取寫鎖,再獲取讀鎖,然后釋放寫鎖。然而,無法從讀鎖升級到寫鎖
。不然就會死鎖。
public void updateData(){writeLock.lock();readLock.lock();out(">>"+"->updateData"+"->hello world!"+source);writeLock.unlock();readLock.unlock();
}
不允許讀鎖后進行寫鎖
,會導致死鎖的。
2. 分布式鎖
基于數(shù)據(jù)庫的分布式鎖
- 原理:利用插入鎖記錄。
基于Redis的分布式鎖
- 原理:利用setNX 設置一個鍵,僅在鍵不存在時設置鍵成功。
- 工具:Redisson已經(jīng)幫我們封裝好分布式鎖。解決了分布式鎖過期續(xù)期問題。
基于ZooKeeper的分布式鎖
- 原理:利用臨時順序節(jié)點
3. 額外的
3.1. synchronized 的鎖升級原理
synchronized 的鎖升級指的是在不同的情況下,synchronized 鎖的狀態(tài)會從偏向鎖、輕量級鎖、重量級鎖等級別逐步升級的過程。在 Java 6 及之前的版本中,synchronized 的鎖升級過程是固定的,而在 Java 6 及之后的版本中,鎖升級過程是根據(jù)當前鎖的狀態(tài)和競爭情況動態(tài)調(diào)整的。
偏向鎖
:當一個線程訪問同步塊并獲取鎖時,會在對象頭中記錄鎖偏向的線程 ID,以后該線程再次進入同步塊時,只需判斷當前線程 ID 是否與對象頭中記錄的線程 ID 相同,如果相同,就可以直接進入同步塊,無需進行額外的同步操作。如果有其他線程競爭鎖,則偏向鎖會被撤銷。
輕量級鎖
:當一個線程獲取鎖失敗時,會嘗試使用輕量級鎖來提高性能。輕量級鎖是通過將對象頭中的信息復制到線程的棧幀中,然后在棧幀中進行同步操作來實現(xiàn)的。如果在同步過程中發(fā)生競爭,則輕量級鎖會升級為重量級鎖。
重量級鎖
:當多個線程競爭同一個鎖時,會升級為重量級鎖。重量級鎖是通過操作系統(tǒng)的互斥量來實現(xiàn)的,每次加鎖和釋放鎖都需要進行系統(tǒng)調(diào)用,開銷較大。
在 Java 6 及之前的版本中,鎖升級過程是固定的,即從偏向鎖升級到輕量級鎖,再升級到重量級鎖。而在 Java 6 及之后的版本中,鎖升級過程是根據(jù)當前鎖的狀態(tài)和競爭情況動態(tài)調(diào)整的,可以根據(jù)實際情況選擇偏向鎖、輕量級鎖或重量級鎖,從而提高程序的性能。
參考文章:
- synchronized 的底層原理
3.2. synchronized鎖原理
是通過對象內(nèi)部的做監(jiān)視器鎖(monitor)實現(xiàn)。監(jiān)視器鎖是依賴于底層的操作系統(tǒng)的 Mutex Lock來實現(xiàn),而操作系統(tǒng)實現(xiàn)線程之間的切換這就需要從用戶態(tài)轉換到核心態(tài),這個成本非常高,狀態(tài)之間的轉換需要相對比較長的時間,這就是為什么Synchronized 效率低的原因。