如何基于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实现一个锁的主要内容,如果未能解决你的问题,请参考以下文章