天天看點

鎖(五):讀寫鎖

  • 讀寫鎖特性
特性:寫寫互斥、讀寫互斥、讀讀共享
鎖降級:寫線程擷取寫入鎖後可以擷取讀取鎖,然後釋放寫入鎖,這樣就從寫入鎖變成了讀取鎖,進而實作鎖降級的特性      
  • 案例1
public class ReentrantReadWriteLockDemo {

    private int i = 0;
    private int j = 0;

    // 擷取鎖
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock readLock = lock.readLock();
    Lock writeLock = lock.writeLock();

    // 使用讀鎖
    public void out(){
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"i的值====》"+i + "j的值====》"+j);
        }finally {
            readLock.unlock();
        }
    }

    // 使用寫鎖
    public void inCreate() {
        writeLock.lock();
        try {
            i++;
            Thread.sleep(500L);
            j++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }

    // 測試
    public static void main(String[] args) {
        ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
        // 測試1,3個線程,先寫後讀
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                reentrantReadWriteLockDemo.inCreate();
                reentrantReadWriteLockDemo.out();
            }).start();
        }
    }

}

# 控制台結果:
Thread-2i的值====》3j的值====》3
Thread-1i的值====》3j的值====》3
Thread-0i的值====》3j的值====》3      
  • debug調試
  • 鎖(五):讀寫鎖
  • 線程0拿到寫鎖,釋放寫鎖
  • 鎖(五):讀寫鎖
  • 執行完畢
  • 鎖(五):讀寫鎖
  • 之後執行線程1和線程2
  • 案例2
public class ReentrantReadWriteLockDemo {

    private int i = 0;
    private int j = 0;

    // 擷取鎖
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock readLock = lock.readLock();
    Lock writeLock = lock.writeLock();

    // 使用讀鎖
    public void out(){
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"i的值====》"+i + "j的值====》"+j);
        }finally {
            readLock.unlock();
        }
    }

    // 使用寫鎖
    public void inCreate() {
        writeLock.lock();
        try {
            i++;
            Thread.sleep(500L);
            j++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }

    // 測試
    public static void main(String[] args) {
        ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
        // 測試2,2個線程,先讀後寫
        new Thread(()->{
            reentrantReadWriteLockDemo.out();
        },"讀線程").start();
        new Thread(()->{
            reentrantReadWriteLockDemo.inCreate();
        },"寫線程").start();
    }

}      
  • debug調試
  • 鎖(五):讀寫鎖
  • 如下:讀線程擷取到鎖,但還沒有釋放
  • 鎖(五):讀寫鎖
  • 切換到寫線程,下一步時報錯如下,說明讀寫是互斥的
  • 鎖(五):讀寫鎖
  • 案例3
public class ReentrantReadWriteLockDemo {

    private int i = 0;
    private int j = 0;

    // 擷取鎖
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock readLock = lock.readLock();
    Lock writeLock = lock.writeLock();

    // 使用讀鎖
    public void out(){
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"i的值====》"+i + "j的值====》"+j);
        }finally {
            readLock.unlock();
        }
    }

    // 使用寫鎖
    public void inCreate() {
        writeLock.lock();
        try {
            i++;
            Thread.sleep(500L);
            j++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }

    // 測試
    public static void main(String[] args) {
        ReentrantReadWriteLockDemo reentrantReadWriteLockDemo = new ReentrantReadWriteLockDemo();
        // 測試3,2個線程,讀讀操作
        new Thread(()->{
            reentrantReadWriteLockDemo.out();
        },"讀線程1").start();
        new Thread(()->{
            reentrantReadWriteLockDemo.out();
        },"讀線程2").start();
    }

}      
  • debug調試
  • 首先讀線程1擷取到鎖,但還沒有釋放
  • 鎖(五):讀寫鎖
  • 切換到讀線程2,下一步,可以擷取到鎖,說明讀讀是共享的