1. 程式人生 > >java併發-重入鎖(ReentrantLock)

java併發-重入鎖(ReentrantLock)

文章目錄

重入鎖(ReentrantLock)

含義

重入鎖,標識在一個執行緒中,可重複對該資源重複加鎖。

  • synchronized就是重入鎖
  • ReentrantLock也支援衝入操作
  • 是排它鎖(獨佔鎖)

針對於AQS實現重入功能
在重寫tryAquiresxxx的時候考慮同一個執行緒多次lock的情況即可

虛擬碼

  • aquire方法
        Thread currentThread = Thread.currentThread();
        //getExclusiveOwnerThread() 標識獨佔模式下的當前執行緒物件引用
        if(currentThread == getExclusiveOwnerThread())
  • release方法
    • 這裡,就是當前執行緒獲取了多次
    • 比如1.lock() 2.lock() 3.unlock() 4.unlock
    • 這裡ReentrantLock的aquire()方法傳入的是1
    • 執行1,2後state分別是 1,2
    • 執行3 c = 2-1 //setState(2-1)
    • 執行4 c = 1-1 //直接釋放
    protected final boolean tryRelease(int releases) {
                //同一個執行緒多次獲取資源鎖的話,state會累加,那麼這裡做累減操作
                int c = getState() - releases;
                //不是當前執行緒去release的話,丟擲monitor異常,當然並不是monitor底層實現的
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                //c == 0的話,就表示不存在一個執行緒獲取多次,那麼直接release
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                //這裡,就是當前執行緒獲取了多次
                //比如1.lock() 2.lock() 3.unlock() 4.unlock
                //這裡ReentrantLock的aquire()方法傳入的是1
                //執行1,2後state分別是 1,2
                //執行3  c = 2-1 //setState(2-1)
                //執行4  c = 1-1 //直接釋放
                setState(c);
                return free;
            }

公平鎖和非公平鎖

  • AQS 預設沒有處理鎖的公平爭奪策略,獲取鎖的邏輯是需要使用者自行定義
  • ReentrantLock實現了公平和非公平
  • 多執行緒下,執行緒去獲取鎖的順序是不固定的
  • 公平鎖比非公平鎖效能要低(需要拒絕獲取,直到該執行緒是head的時候才會成功獲得資源鎖)

Node連結串列 head–>N1(pre,next)–>N2(pre,next)<–tail

    
    //true 標識在佇列中的該執行緒擁有前置節點
    //false 該執行緒是head或者 null==null即空佇列 tail==head==null
      
    public final boolean hasQueuedPredecessors() {
               Node t = tail; // Read fields in reverse initialization order
               Node h = head;
               Node s;
               return h != t &&
                   ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    
    protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                //非公平鎖  沒有hasQueuedPredecessors()方法
                    if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
    }

公平鎖最終獲得鎖的順序和佇列中的順序是一致的,FIFO

公平與非公平效能

  • 公平鎖能保證FIFO規則,但是增加了執行緒切換的次數

為什麼?

AQS操作雖然使用CAS無鎖操作機制,但是,CPU在排程的時候,切換至該執行緒的時候,該執行緒去獲取該資源鎖,但是FIFO原則,無法獲取鎖,將處於自旋操作,後續執行緒任務無法執行,cpu排程結束,就切換至下一個執行緒。

公平鎖大大的增加了CPU執行緒排程次數,導致吞吐率(TPS)降低

  • 非公平鎖,只要該執行緒獲得到CPU時間片,那麼在沒有執行緒獲取鎖的時候,就可以得到鎖,執行任務,減少了執行緒切換,提高了TPS。

使用

/**
 * describe:
 * E-mail:[email protected]  date:2018/12/16
 *
 * @Since 0.0.1
 */
public class ReentRantLockTest {

    //預設構造是非公平
    //true是公平鎖
    //false是非公平鎖
    public static final Lock lock = new ReentrantLock(true);

    static class T extends Thread {
        public T(String name){
            super(name);
        }
        @Override
        public void run() {
            lock.lock();
            System.out.println("==" + Thread.currentThread().getName());
            try {
                //Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            test.T t = new test.T(String.valueOf(i+"Thread"));
            t.start();
        }
        System.out.println(null == null);
    }
}

不公平鎖
在這裡插入圖片描述

公平鎖
在這裡插入圖片描述

GitHub主頁