1. 程式人生 > >併發系列(十一)----- ReentrantLock的使用

併發系列(十一)----- ReentrantLock的使用

一 簡介

ReentrantLock在中文的意思是重入鎖與synchronized同步語意一樣(具體的區別下面會總結),重入的意思是一個執行緒可以多次加鎖,但是釋放鎖的時候要釋放加鎖的次數。ReentrantLock實現就是利用AQS獨佔模式,內部維護了一個AQS的子類Sync,Sync有兩個子類FairSync和NofairSync這兩個分別是ReentrantLock的兩種鎖,公平鎖和非公平鎖(公平鎖與非公平鎖介紹)。因為ReentrantLock利用了AQS的獨佔模式,那麼ReentrantLock就可以使用等待佇列的相關功能。

二 ReentrantLock的簡單使用

如果只是簡單使用ReentrantLock,不使用同步佇列的話是比較簡單。使用方式如下

    /**
     * ReentrantLock預設是非公平鎖 公平鎖的建立 private static final ReentrantLock lock = new ReentrantLock(true);
     */
    private static final ReentrantLock lock = new ReentrantLock();
    public void doSomeThing(){
        lock.lock();
        try {
            //執行業務邏輯,在這裡操作可保證執行緒安全
        }finally {
            lock.unlock();
        }
    }

使用方式是比較簡單,但是ReentrantLock提供加鎖的方式卻有不同的方式,具體說明如下

鎖定釋放只有一個方法unlock()。

三 ReentrantLock等待佇列的使用

在ReentrantLock中的Condition提供了Object中的wait(),和notify(),notifyAll()的功能,其中在Condition中的await開頭的方法與Object中的wait具有相同的功能,Condition中的signal()和signalAll()分別相當與Object中的notify()和notifyAll(),其中一個lock總可已有多個Condition

下面看程式碼

 private static ReentrantLock lock = new ReentrantLock();

    private static Condition condition = lock.newCondition();

    public static void main(String[] args) {


        final Thread hh = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread() + "等待條件完成");
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(Thread.currentThread() + "終於等到條件完成了");
                    lock.unlock();
                }
            }
        });
        hh.start();

        final Thread qq = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread() + "條件完成了");
                    this.notifyAll();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });
        qq.start();
    }

下面是等待相關的方法說明

喚醒的話是兩個方法signal()和singalAll()兩個方法,作用的話看方法名就知道了。一個是隻喚醒一個,一個是喚醒所有。

四 與synchronized的區別

ReentrantLock和synchronized具有相同的功能,在效能上不會有太大的差別,如果既可以用ReentrantLock也可以用synchronized的話,官方的建議是使用synchronized。因為synchronized在使用的時候比較方便的不用考慮釋放鎖,而ReentrantLock如果沒有釋放的話會是其它執行緒一直處於waiting狀態中。但是ReentrantLock也有它特有的功能

1.      ReenTrantLock可以指定是公平鎖還是非公平鎖。而synchronized只能是非公平鎖。所謂的公平鎖就是先等待的執行緒先獲得鎖。

2.      ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的執行緒們,而不是像synchronized要麼隨機喚醒一個執行緒要麼喚醒全部執行緒。

3.      ReenTrantLock提供了一種能夠中斷等待鎖的執行緒的機制lock()方法

在同步的時候有上面3需要ReentrantLock的功能可以使用ReenTrantLock,在其他的情況下聽官方的。