Java多線程 ReadWriteLock、StampedLock用法

無論是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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章