如何基于aqs实现一个锁

Posted 阿里-马云的学习笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何基于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实现一个锁的主要内容,如果未能解决你的问题,请参考以下文章

java-基于AQS实现锁

老板让只懂Java基本语法的我,基于AQS实现一个锁

AQS详解之独占锁模式

AQS(面试)

多线程(十AQS原理-ReentrantLock实现)

9AQS实现重入锁