廖雪峯Java11多線程編程-3高級concurrent包-2ReadWriteLock

1.ReentrantLock的限制

ReentrantLock保證了只有一個線程能夠執行臨界區代碼。 <font color="green">臨界區代碼:任什麼時候候只有1個線程能夠執行的代碼塊。 臨界區指的是一個訪問共用資源(例如:共用設備或是共用存儲器)的程序片斷,而這些共用資源又沒法同時被多個線程訪問的特性。當有線程進入臨界區段時,其餘線程或是進程必須等待,有一些同步的機制必須在臨界區段的進入點與離開點實現,以確保這些共用資源是被互斥得到使用,例如:semaphore。只能被單一線程訪問的設備,例如:打印機。</font>java

public void inc(){    
    lock.lock();
    try{
        value += 1;
    }finally{
        lock.unlock();
    }
}
public int get(){    
    lock.lock();
    try(){
        return value;
    }finally{
        lock.unlock();
    }
}

但有時候,這種保護有些過頭:瀏覽器

  • 由於咱們發現任什麼時候刻只容許1個線程修改,對inc()進行加鎖是必須的。
  • 可是get()方法只讀取數據,不修改數據。它應該容許多個線程同時調用。

咱們指望:容許多個線程同時讀,但只要有一個線程在寫,其餘線程就必須等待。性能

2. ReadWriteLock

使用ReadWriteLock能夠解決:this

  • 只容許一個線程寫入(其餘線程既不能寫入,也不能讀取)
  • 沒有寫入時,多個線程容許同時讀(提升性能)
  • 實現
class Counter{
    final ReadWriteLock lock = new ReentrantReadWriteLock();
    //分別得到readLock和writeLock
    final Lock rlock = lock.readLock();
    final Lock wlock = lock.writeLock();
    private int value = 0;
    public void inc(){
        wlock.lock();
        try{
            value += 1;
        }finally {
            wlock.unlock();
        }
    }
    public int get(){
        rlock.lock();
        try{
            return this.value;
        }finally {
            rlock.unlock();
        }
    }
}

3.示例

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class Count{
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    private Lock rlock = lock.readLock();
    private  Lock wlock = lock.writeLock();
    private int value = 0;
    public void add(int m){
        wlock.lock();
        try{
            value += m;
        }finally {
            wlock.unlock();
        }
    }
    public void dec(int m){
        wlock.lock();
        try{
            value -= m;
        }finally {
            wlock.unlock();
        }
    }
    public int get(){
        rlock.lock();
        try{
            return value;
        }finally {
            rlock.unlock();
        }
    }
}
public class Main{
    final static int LOOP = 100;
    public static void main(String[] args) throws Exception{
        Count count = new Count();
        Thread t1 = new Thread(){
            public void run(){
                for(int i=0;i<LOOP;i++){
                    count.add(1);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                for(int i=0;i<LOOP;i++){
                    count.dec(1);
                }
            }
        };
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count.get());
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190612202639771-792089703.png" width="500" />spa

ReadWriteLock適用條件:線程

  • 同一個實例,有大量線程讀取,僅有少數線程修改。
  • 例如論壇帖子,回覆視爲寫入,不頻繁操做;瀏覽器看做讀取,很是頻繁。這種狀況下,就能夠適用ReadWriteLock

4. 總結:

使用ReadWriteLock能夠提升讀取效率:code

  • ReadWriteLock只容許一個線程寫入。
  • ReadWriteLock容許多個線程同時讀取。
  • ReadWriteLock適合讀多寫少的場景。
相關文章
相關標籤/搜索