如何基於aqs實現一個鎖


AQS是java中並發的半壁江山,什么ReetrantLock、Condition、ReetrantReadWriteLock等,都是基於AQS實現。

一、AQS使用方式以及設計模式

AQS使用了模板模式,所謂的模板模式,通過一個例子來看-----以設計房子為例

1、模板抽象類:HouseTemplate

public abstract class HouseTemplate {

    protected HouseTemplate(String name){
        this.name = name;
    }

    protected String name;

    protected abstract void buildDoor();

    protected abstract void buildWindow();

    protected abstract void buildWall();

    protected abstract void buildBase();

    //公共邏輯
    public final void buildHouse(){

        buildBase();
        buildWall();
        buildDoor();
        buildWindow();

    }

}

2、子類1:HouseOne

public class HouseOne extends HouseTemplate {

    HouseOne(String name){
        super(name);
    }

    @Override
    protected void buildDoor() {
        System.out.println(name +"的門要采用防盜門");
    }

    @Override
    protected void buildWindow() {
        System.out.println(name + "的窗戶要面向北方");
    }

    @Override
    protected void buildWall() {
        System.out.println(name + "的牆使用大理石建造");
    }

    @Override
    protected void buildBase() {
        System.out.println(name + "的地基使用鋼鐵地基");
    }
    
}

3、子類2:HouseTwo

public class HouseTwo extends HouseTemplate {

    HouseTwo(String name){
        super(name);
    }

    @Override
    protected void buildDoor() {
        System.out.println(name + "的門采用木門");
    }

    @Override
    protected void buildWindow() {
        System.out.println(name + "的窗戶要向南");
    }

    @Override
    protected void buildWall() {
        System.out.println(name + "的牆使用玻璃制造");
    }

    @Override
    protected void buildBase() {
        System.out.println(name + "的地基使用花崗岩");
    }

}

4、測試類:Clienter

public class Clienter {

    public static void main(String[] args){
        HouseTemplate houseOne = new HouseOne("房子1");
        HouseTemplate houseTwo = new HouseTwo("房子2");
        houseOne.buildHouse();
        houseTwo.buildHouse();
    }

}

運行結果:

房子1的地基使用鋼鐵地基
房子1的牆使用大理石建造
房子1的門要采用防盜門
房子1的窗戶要面向北方
房子2的地基使用花崗岩
房子2的牆使用玻璃制造
房子2的門采用木門
房子2的窗戶要向南


房子1的地基使用鋼鐵地基
房子1的牆使用大理石建造
房子1的門要采用防盜門
房子1的窗戶要面向北方
房子2的地基使用花崗岩
房子2的牆使用玻璃制造
房子2的門采用木門
房子2的窗戶要向南

通過以上例子,我們認識了模板模式中的基本方法和模板方法,其中HouseTemplate中的buildHouse方法就是基本方法,其余四個均為模板方法。其中基本方法一般會用final修飾,保證其不會被子類修改,而模板方法則使用protected修飾,表明其需要在子類中實現。

AQS也是基於這種模式來實現的,所以如果你要自己實現一個鎖,就需要針對性的覆蓋與實現AQS的某些方法。當然AQS這么強大,提供了獨占式鎖以及共享式鎖的功能,你需要根據獨占還是共享來選擇實現哪些方法。

獨占式:

1、獲取

tryAcquire

accquire

acquireInterruptibly

tryAcquireNanos

2、釋放

tryRelease

release

共享式:

1、獲取

tryAcquireShared

acquireShared

acquireSharedInterruptibly

tryAcquireSharedNanos

2、釋放

tryReleaseShared

releaseShared

獨占式、共享式都要實現的方法

1、這個同步器是否處於獨占模式  isHeldExclusively

2、同步狀態state:

  getState:獲取當前的同步狀態

  setState:設置當前同步狀態

  compareAndSetState 使用CAS設置狀態,保證狀態設置的原子性

二、基於AQS自實現的鎖(獨占式)

package com.xiangxue.ch4.aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 *類說明:實現一個自己的類ReentrantLock
 */
public class SelfLock implements Lock{
    
    //state 表示獲取到鎖 state=1 獲取到了鎖,state=0,表示這個鎖當前沒有線程拿到
    private static class Sync extends AbstractQueuedSynchronizer{
        
        //是否占用
        protected boolean isHeldExclusively() {
            return getState()==1;
        }
        
        //通過state維護當前是否有線程拿到鎖,獲取鎖也就是通過CAS的方式將state從0設置為1,成功后將獨占鎖設置為自己
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        
        //這地方不用使用CAS的原因是釋放鎖只有當前拿到鎖的一個線程可以釋放,所以不存在競爭條件
        protected boolean tryRelease(int arg) {
            if(getState()==0) {
                throw new UnsupportedOperationException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        
        Condition newCondition() {
            return new ConditionObject();
        }
    }
    
    private final Sync sycn = new Sync();

    @Override
    public void lock() {
        sycn.acquire(1);
        
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sycn.acquireInterruptibly(1);
        
    }

    @Override
    public boolean tryLock() {
        return sycn.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sycn.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sycn.release(1);
        
    }

    @Override
    public Condition newCondition() {
        return sycn.newCondition();
    }


}

三、基於AQS自實現的鎖(共享式)

package com.xiangxue.ch4.aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;

/**
 *類說明:自定義共享鎖
 */
public class TrinityLock   {

    //為3表示允許兩個線程同時獲得鎖
    private final Sync sync = new Sync(3);

    private static final class Sync extends AbstractQueuedSynchronizer {
        
        Sync(int count) {
            if (count <= 0) {
                throw new IllegalArgumentException("count must large than zero.");
            }
            setState(count);
        }

        public int tryAcquireShared(int reduceCount) {
            for (;;) {
                int current = getState();
                int newCount = current - reduceCount;
                if (newCount < 0 || compareAndSetState(current, newCount)) {
                    return newCount;
                }
            }
        }

        public boolean tryReleaseShared(int returnCount) {
            for (;;) {
                int current = getState();
                int newCount = current + returnCount;
                if (compareAndSetState(current, newCount)) {
                    return true;
                }
            }
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }

    public void lock() {
        sync.acquireShared(1);
    }

    public void unlock() {
        sync.releaseShared(1);
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public boolean tryLock() {
        return sync.tryAcquireShared(1) >= 0;
    }

    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
    }

    public Condition newCondition() {
        return sync.newCondition();
    }
}

簡單來說,就是將state初始化>1,表示一共可以有多個線程占有,不過這種沒有實現讀跟寫的分離。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM