ReadWriteLock包括兩種子鎖:
1. ReadWriteLock ReadWriteLock 可以實現(xiàn)多個讀鎖同時進行,但是讀與寫和寫于寫互斥,只能有一個寫鎖線程在進行。
2. StampedLock StampedLock是Jdk在1.8提供的一種讀寫鎖,相比較ReentrantReadWriteLock性能更好,因為ReentrantReadWriteLock在讀寫之間是互斥的,使用的是一種悲觀策略,在讀線程特別多的情況下,會造成寫線程處于饑餓狀態(tài),雖然可以在初始化的時候設(shè)置為true指定為公平,但是吞吐量又下去了,而StampedLock是提供了一種樂觀策略,更好的實現(xiàn)讀寫分離,并且吞吐量不會下降。
StampedLock包括三種鎖:
1. 寫鎖writeLock:
writeLock是一個獨占鎖寫鎖,當(dāng)一個線程獲得該鎖后,其他請求讀鎖或者寫鎖的線程阻塞, 獲取成功后,會返回一個stamp(憑據(jù))變量來表示該鎖的版本,在釋放鎖時調(diào)用unlockWrite方法傳遞stamp參數(shù)。提供了非阻塞式獲取鎖tryWriteLock。
2. 悲觀讀鎖readLock:
readLock是一個共享讀鎖,在沒有線程獲取寫鎖情況下,多個線程可以獲取該鎖。如果有寫鎖獲取,那么其他線程請求讀鎖會被阻塞。悲觀讀鎖會認為其他線程可能要對自己操作的數(shù)據(jù)進行修改,所以需要先對數(shù)據(jù)進行加鎖,這是在讀少寫多的情況下考慮的。請求該鎖成功后會返回一個stamp值,在釋放鎖時調(diào)用unlockRead方法傳遞stamp參數(shù)。提供了非阻塞式獲取鎖方法tryWriteLock。
3. 樂觀讀鎖tryOptimisticRead:
tryOptimisticRead相對比悲觀讀鎖,在操作數(shù)據(jù)前并沒有通過CAS設(shè)置鎖的狀態(tài),如果沒有線程獲取寫鎖,則返回一個非0的stamp變量,獲取該stamp后在操作數(shù)據(jù)前還需要調(diào)用validate方法來判斷期間是否有線程獲取了寫鎖,如果是返回值為0則有線程獲取寫鎖,如果不是0則可以使用stamp變量的鎖來操作數(shù)據(jù)。
由于tryOptimisticRead并沒有修改鎖狀態(tài),所以不需要釋放鎖。
這是讀多寫少的情況下考慮的,不涉及CAS操作,所以效率較高,在保證數(shù)據(jù)一致性上需要復(fù)制一份要操作的變量到方法棧中,并且在操作數(shù)據(jù)時可能其他寫線程已經(jīng)修改了數(shù)據(jù),而我們操作的是方法棧里面的數(shù)據(jù),也就是一個快照,所以最多返回的不是最新的數(shù)據(jù),但是一致性得到了保證。