如何基于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();
    }

}

原文地址:https://www.cnblogs.com/alimayun/p/12153034.html

时间: 2024-10-29 17:17:22

如何基于aqs实现一个锁的相关文章

基于AQS的锁

锁分为独占锁和共享锁,它们的主要实现都是依靠AbstractQueuedSynchronizer,这个类只提供一系列公共的方法,让子类来调用.基于我了解不深,从这个类的属性,方法,和独占锁的获取方式去了解这个类. AbstractQueuedSynchronizer的主要属性和方法: 属性/方法 含    义 Thread exclusiveOwnerThread 这个是AQS父类AbstractOwnableSynchronizer的属性,表示独占模式同步器的当前拥有者 Node 上面已经介绍

AQS实现公平锁和非公平锁

基于AQS的锁(比如ReentrantLock)原理大体是这样:有一个state变量,初始值为0,假设当前线程为A,每当A获取一次锁,status++. 释放一次,status--.锁会记录当前持有的线程.当A线程拥有锁的时候,status>0. B线程尝试获取锁的时候会对这个status有一个CAS(0,1)的操作,尝试几次失败后就挂起线程,进入一个等待队列.如果A线程恰好释放,--status==0, A线程会去唤醒等待队列中第一个线程,即刚刚进入等待队列的B线程,B线程被唤醒之后回去检查这

分布式锁(1) ----- 介绍和基于数据库的分布式锁

线程锁与分布式锁 1.java的synchronize和Lock都是属于线程锁,只能保证同一个进程内的多线程对共享变量修改访问同步.它们的原理都是设置一个可以让所有线程访问到标记,如synchronize是设置对象头的Mark Word,而Lock类是基于AQS的volatile修饰的state. 2.分布式锁是属于进程范畴的,而且进程可以在不同的机器上.它要保证的是多个进程对共享变量修改访问同步(例如集群环境下同时修改缓存和数据库).分布式锁也同样需要一个可以让所有进程访问到的标记(如数据库的

ReentrantLock是如何基于AQS实现的

ReentrantLock是一个可重入的互斥锁,基于AQS实现,它具有与使用 synchronized 方法和语句相同的一些基本行为和语义,但功能更强大. lock和unlock ReentrantLock 中进行同步操作都是从lock方法开始.lock获取锁,进行一系列的业务操作,结束后使用unlock释放锁. private final ReentrantLock lock = new ReentrantLock(); public void sync(){ lock.lock(); try

AtomicInteger源码分析——基于CAS的乐观锁实现

AtomicInteger源码分析--基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及到清空寄存器,缓存数据.然后重新加载新的thread所需数据.当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,在通过notify(),notifyAll()唤醒回来.在某个资源不可用的时候,就将cpu让出,把当前等待线程切换为阻

基于Redis的分布式锁到底安全吗(上)?

网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现算法也看似合乎逻辑,但当我们着手去实现它们的时候,却发现如果你越是仔细推敲,疑虑也就越来越多. 实际上,大概在一年以前,关于Redis分布式锁的安全性问题,在分布式系统专家Martin Kleppmann和Redis的作者antirez之间就发生过一场争论.由于对这个问题一直以来比较关注,所以我前些日子仔细阅读了与这场争

一次基于etcd的分布式锁自动延时失败问题的排查

今天在测试基于etcd的分布式锁过程中,在测试获取锁后,释放之前超出TTL时长的情况下自动延长TTL这部分功能,在延长指定key的TTL时总是返回404错误信息,在对目标KEY更新TTL时目标KEY已不存在. 最终问题排查为ETCD集群3个节点之间的系统时间不一致,因为TTL延长是在KEY创建后单独一个监听线程中进行,在TTL过半之后会更新TTL,因此可能出现更新TTL之前,由于集群中时间超前的节点将目标KEY删除,导致更新TTL时找不到目标KEY的错误. 同步集群所有节点系统时间后问题排除:

基于OR1200的一个简单SOPC

以下内容摘自<步步惊芯--软核处理器内部设计分析>一书 在本书第2章建立了最小系统,最小系统只由CPU.QMEM模块组成,借助于最小系统,我们分析了OR1200各类指令的执行过程.熟悉了流水线的工作原理以及CPU内部各个模块的代码实现,第10章在最小系统上增添了IMMU.DMMU模块,借此分析了OR1200中内存管理单元的实现原理.本章将建立一个基于OR1200的简单SOPC,后面的示例程序将运行在这个简单SOPC之上,借助于该SOPC分析OR1200中ICache.DCache.Wishbo

基于ZooKeeper的分布式锁和队列

在分布式系统中,往往需要一些分布式同步原语来做一些协同工作,上一篇文章介绍了Zookeeper的基本原理,本文介绍下基于Zookeeper的Lock和Queue的实现,主要代码都来自Zookeeper的官方recipe. 锁(Lock) 完全分布式锁是全局同步的,这意味着在任何时刻没有两个客户端会同时认为它们都拥有相同的锁,使用 Zookeeper 可以实现分布式锁,需要首先定义一个锁节点(lock root node). 需要获得锁的客户端按照以下步骤来获取锁: 保证锁节点(lock root