zoukankan      html  css  js  c++  java
  • 如何基于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,表示一共可以有多个线程占有,不过这种没有实现读跟写的分离。

  • 相关阅读:
    xilinx下载器,JTAG-HS3和Platform Cable USB II 速度对比
    LATTICE下载器HW-USBN-2B使用说明
    altera下载器高速版本 PL-USB2-BLASTER 使用说明
    FPGA流程设计
    关于fpga的后仿真重要性
    使用MyBatis分页插件PageHelper遇到的问题
    java 面试题总结01
    netty Demo
    netty 概念篇
    pom.xml 简述
  • 原文地址:https://www.cnblogs.com/alimayun/p/12153034.html
Copyright © 2011-2022 走看看