1. 程式人生 > 實用技巧 >《Java高併發程式設計》 --通過ReentrantLock觀望Java鎖機制

《Java高併發程式設計》 --通過ReentrantLock觀望Java鎖機制

多執行緒鎖有兩種:

一種是用關鍵字 : syncronized實現

另一種是用Lock的實現類實現。 關於syncronized的解釋可以參考一位博主寫的(https://www.cnblogs.com/yuhangwang/p/11295940.html

這裡就先看ReentrantLock的實現,去窺探java的鎖機制。

首先整體流程圖如下:

示例程式碼:

public class TestTryLock implements Runnable {
    private static Lock locks = new ReentrantLock();
    @Override
    
public void run() { try { if(locks.tryLock(4, TimeUnit.SECONDS)){ // lock.lock() System.out.println(Thread.currentThread().getName()+"-->"); Thread.sleep(3000); }else{ System.out.println(Thread.currentThread().getName()+" time out "); } }
catch (InterruptedException e) { // e.printStackTrace(); }finally { locks.unlock();//會丟擲鎖物件的異常,因為沒有獲取鎖在unlock的時候出異常,可以先判斷一下是否存在在執行。 } } public static void main(String[] args) throws InterruptedException { TestTryLock test =new TestTryLock(); Thread t1
= new Thread(test,"t1"); Thread t2 = new Thread(test,"t2"); Thread t3 = new Thread(test,"t3"); t1.start(); t2.start(); t1.join(); t2.join(); } }

示例用使用的是 ReentrantLock的非公平鎖的實現,即執行緒不需要按照申請資源的順序進行搶佔鎖資源。

通過使用lock.lock() 和lock.unlock()的配合,進行對資源的加解鎖。

final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

lock.lock() 是執行緒對資源進行繫結的操作,當執行緒佔有了該共享資源(lock)的時候,會在 AQS同步器中的

exclusiveOwnerThread 屬性設定當前搶佔執行緒的值。 並將state設定為 1 。

如果沒有搶佔到資源的時候,就會走acquire(1)的路子。 也就是會將沒有搶到鎖的執行緒丟進等待佇列中,這是一個FIFO佇列

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}

然後不斷的進行自旋等待,判斷前一節點是不是頭節點,當原先搶佔了資源鎖的執行緒進行lock.unlock()等操作時,

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

也就是呼叫了AQS的release操作。 就會將state - 1 處理,一旦state == 0,則就說明可以釋放鎖了。

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

如果等待佇列中某節點的前一節點是頭節點,該節點就開始申請搶佔 AQS中的

exclusiveOwnerThread。 如果成功了,就離開等待佇列,進入到執行狀態。


以上。