無論是synchronized機制,還是ReentrantLock加鎖,實際上只有一個線程可以執行臨界區代碼。即讀寫、寫讀、讀讀、寫寫 兩個線程之間是相互阻塞的。然而讀線程之間是需要併發的,Java使用ReadWriteLock實現多個線程同時讀提高併發性能。
1、ReadWriteLock
import java.util.Arrays; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RWLock { public static void main(String[] args) { var point = new Pixel(); Thread t1 = new Thread() { @Override public void run() { for (int i = 0; i < 10; i++) { point.move(i, i); } } }; t1.start(); for (int j = 0; j < 10; j++) { Thread t = new Thread() { @Override public void run() { point.getPosition(); } }; t.start(); } } } class Pixel { private int[] position = { 0, 0 }; private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock writeLock = lock.writeLock(); private final Lock readLock = lock.readLock(); public void move(int i, int j) { writeLock.lock(); try { this.position[0] = i; this.position[1] = j; } finally { writeLock.unlock(); } } public void getPosition() { readLock.lock(); try { System.out.println(Arrays.toString(this.position)); } finally { readLock.unlock(); } } }
ReadWriteLock 的用法:在需要加寫鎖的地方調用 writeLock.lock(); 在需要加讀鎖的地方調用 readLock.lock();
ReadWriteLock保證多個線程可以同時獲取讀鎖,但讀寫,寫讀,寫寫線程之間仍然是阻塞的。
2、StampedLock
由於ReadWriteLock在讀的過程中不允許寫,這是一種悲觀的讀鎖,Java 8引入了新的讀寫鎖 StampedLock,允許讀的過程中寫入,這是一種樂觀的讀鎖。
class Point { private final StampedLock stampedLock = new StampedLock(); private double x; private double y; public void move(double x1, double y1) { long stamp = stampedLock.writeLock(); try { this.x += x1; this.y += y1; } finally { stampedLock.unlock(stamp); } } public double getDistance() { long stamp = stampedLock.tryOptimisticRead(); double x2 = this.x; double y2 = this.y; if (stampedLock.validate(stamp)) { stamp = stampedLock.readLock(); try { x2 = this.x; y2 = this.y; } finally { stampedLock.unlock(stamp); } } return Math.sqrt(x2 * x2 + y2 * y2); } }
需要注意的是:
1、StampedLock 獲取鎖的方法會返回一個郵戳(Stamp);
2、釋放鎖的方法也需要一個郵戳(Stamp);
3、StampedLock是不可重入的;
4、StampedLock有三種訪問模式:
- Reading(讀模式):功能和ReentrantReadWriteLock的讀鎖類似
- Writing(寫模式):功能和ReentrantReadWriteLock的寫鎖類似
- Optimistic reading(樂觀讀模式):這是一種優化的讀模式。
5、StampedLock支持讀鎖和寫鎖的相互轉換;
6、無論寫鎖還是讀鎖,都不支持Conditon等待。
參考鏈接:
https://segmentfault.com/a/1190000015808032
https://www.liaoxuefeng.com/wiki/1252599548343744/1309138673991714