AQS(AbstractQueuedSynchronizer)抽象队列同步器

AQS(AbstractQueuedSynchronizer)抽象队列同步器
AQS是并发编程包里面的一个抽象类
在这里插入图片描述
实现的子类有哪些,基于AQS实现了,线程池里面用到了,显示锁用到了,读写锁用到了,信号量用到了…

JDK并发里面的同步组件的一个基础的构件,用来构建同步组件

AQS中比较重要的成员变量:state 同步状态

    /**
     * The synchronization state.
     */
    private volatile int state;

模板方法的设计模式

模版方法:

做一件事情 dosomething
Dosomething (){
    doFirst();
    doSecond();
    …
    doTenth();
}

用模版方法做蛋糕:

/**
 * 类说明:抽象蛋糕模型
 */
public abstract class AbstractCake {
    protected abstract void shape();/*造型*/
    protected abstract void apply();/*涂抹*/
    protected abstract void brake();/*烤面包*/

    /*做个蛋糕 */
    public final void run(){
        this.shape();
        this.apply();
        this.brake();
    }

}
/**
 * 类说明:芝士蛋糕
 */
public class CheeseCake  extends AbstractCake {

    @Override
    protected void shape() {
        System.out.println("芝士蛋糕造型");
    }

    @Override
    protected void apply() {
        System.out.println("芝士蛋糕涂抹");
    }

    @Override
    protected void brake() {
        System.out.println("芝士蛋糕烘焙");
    }
}
/**
 * 类说明:奶油蛋糕
 */
public class CreamCake extends AbstractCake {
    @Override
    protected void shape() {
        System.out.println("奶油蛋糕造型");
    }

    @Override
    protected void apply() {
        System.out.println("奶油蛋糕涂抹");
    }

    @Override
    protected void brake() {
        System.out.println("奶油蛋糕烘焙");
    }
}
/**
 * 类说明:生产蛋糕
 */
public class MakeCake {
    public static void main(String[] args) {
        AbstractCake cheeseCake = new CheeseCake();
        AbstractCake creamCake = new CreamCake();
        cheeseCake.run();
        creamCake.run();
    }
}
芝士蛋糕造型
芝士蛋糕涂抹
芝士蛋糕烘焙
奶油蛋糕造型
奶油蛋糕涂抹
奶油蛋糕烘焙

实现自己的同步类的时候就是用模版方法,只要实现其中几个方法就行了
比如要实现独占锁,就要实现AQS里面的独占的方法:
tryAcquire本身是没有任何实现的,调用它会抛出异常,这个方法是要我们去实现的

protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

比如要实现共享同步组件类:

protected int tryAcquireShared(int arg) {
    throw new UnsupportedOperationException();
}

实现一个类似于ReentrantLock的锁 (显示锁)

显示锁继承Lock接口
在这里插入图片描述
要实现独占锁,拿锁lock()、释放锁unlock() 一定要实现,这两个方法如何实现,就要借助AQS

/**
 *类说明:实现我们自己独占锁,不可重入
 */
public class SelfLock implements Lock {
    // 静态内部类,自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {

        /*判断处于占用状态*/
        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }

        /*获得锁*/
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
                //Exclusive排他的独占的
                //拿到这把锁后就承包了,排他
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /*释放锁*/
        @Override
        protected boolean tryRelease(int arg) {
            if(getState()==0){
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /* 返回一个Condition,每个condition都包含了一个condition队列*/
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    /* 仅需要将操作代理到Sync上即可*/
    private final Sync sync = new Sync();


    //调用内部类的两个方法就行了
    public void lock() {
    	System.out.println(Thread.currentThread().getName()+" ready get lock");
        sync.acquire(1); //acquire方法里面调用的是tryAcquire
        System.out.println(Thread.currentThread().getName()+" already got lock");
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
    	System.out.println(Thread.currentThread().getName()+" ready release lock");
        sync.release(1);
        System.out.println(Thread.currentThread().getName()+" already released lock");
    }

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

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

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

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}
/**
 *
 *类说明:测试我们自己的独占锁的实现
 */
public class TestMyLock {

    public void test() {
        final Lock lock = new SelfLock();
        class Worker extends Thread {

			public void run() {
                lock.lock();
                System.out.println(Thread.currentThread().getName());
                try {
                    SleepTools.second(1);
                } finally {
                    lock.unlock();
                }
            }
        }
        // 启动4个子线程
        for (int i = 0; i < 4; i++) {
            Worker w = new Worker();
            //w.setDaemon(true);
            w.start();
        }
        // 主线程每隔1秒换行
        for (int i = 0; i < 10; i++) {
        	SleepTools.second(1);
            //System.out.println();
        }
    }

    //四个线程打印名字
    public static void main(String[] args) {
        TestMyLock testMyLock = new TestMyLock();
        testMyLock.test();
    }
}
Thread-0 ready get lock
Thread-2 ready get lock
Thread-2 already got lock
Thread-2
Thread-1 ready get lock
Thread-3 ready get lock
Thread-2 ready release lock
Thread-2 already released lock
Thread-1 already got lock
Thread-1
Thread-1 ready release lock
Thread-1 already released lock
Thread-0 already got lock
Thread-0
Thread-0 ready release lock
Thread-3 already got lock
Thread-3
Thread-0 already released lock
Thread-3 ready release lock
Thread-3 already released lock

调用acquire模版方法,acquire里面的tryAcquire方法是需要我们去实现的

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

AQS的基本思想CLH队列锁
基于链表的自旋锁
CLH三个人的名字头字母即Craig, Landin, and Hagersten (CLH) locks
任意时刻只有一个线程拿到锁,其他的线程在外面排队,拿锁的线程释放了会唤醒线程去竞争锁,没有拿到锁的线程都要排队,一一排好队形成一个链表
凡是要排队的线程,打包成一个QNode,里面至少有三个变量:当前线程、myPred(前驱节点)、locked(=true需要获得锁)
每一个节点都在不停地自旋检测前一个节点有没有释放锁(locked==false)
AQS的基本思想是会不断的自旋,在具体的实现上是双向列表,不会自旋很多次,两次自旋失败后就会把当前线程挂起
在这里插入图片描述
回头看Lock的实现

锁的可重入
改一下tryAcquire方法,判断是我自己的话state+1

/**
 *类说明:实现我们自己独占锁,可重入
 */
public class ReenterSelfLock implements Lock {
    /* 静态内部类,自定义同步器*/
    private static class Sync extends AbstractQueuedSynchronizer {

        /* 是否处于占用状态*/
        protected boolean isHeldExclusively() {
            return getState() > 0;
        }

        /* 当状态为0的时候获取锁*/
        public boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }else if(getExclusiveOwnerThread()==Thread.currentThread()){
                setState(getState()+1);
                return  true;
            }
            return false;
        }

        /* 释放锁,将状态设置为0*/
        protected boolean tryRelease(int releases) {
            if(getExclusiveOwnerThread()!=Thread.currentThread()){
                throw new IllegalMonitorStateException();
            }
            if (getState() == 0)
                throw new IllegalMonitorStateException();

            setState(getState()-1);
            if(getState()==0){
                setExclusiveOwnerThread(null);
            }
            return true;
        }

        /* 返回一个Condition,每个condition都包含了一个condition队列*/
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    /* 仅需要将操作代理到Sync上即可*/
    private final Sync sync = new Sync();

    public void lock() {
    	System.out.println(Thread.currentThread().getName()+" ready get lock");
        sync.acquire(1);
        System.out.println(Thread.currentThread().getName()+" already got lock");
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
    	System.out.println(Thread.currentThread().getName()+" ready release lock");
        sync.release(1);
        System.out.println(Thread.currentThread().getName()+" already released lock");
    }

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

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

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

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}
public class TestReenterSelfLock {

    static final Lock lock = new ReenterSelfLock();

    public void reenter(int x){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+":递归层级:"+x);
            int y = x - 1;
            if (y==0) return;
            else{
                reenter(y);
            }
        } finally {
            lock.unlock();
        }

    }

    public void test() {
        class Worker extends Thread {
			public void run() {
                System.out.println(Thread.currentThread().getName());
                SleepTools.second(1);
                reenter(3);
            }
        }
        // 启动3个子线程
        for (int i = 0; i < 3; i++) {
            Worker w = new Worker();
            w.start();
        }
        // 主线程每隔1秒换行
        for (int i = 0; i < 100; i++) {
        	SleepTools.second(1);
        }
    }

    public static void main(String[] args) {
        TestReenterSelfLock testMyLock = new TestReenterSelfLock();
        testMyLock.test();
    }
}
Thread-0
Thread-1
Thread-2
Thread-0 ready get lock
Thread-0 already got lock
Thread-0:递归层级:3
Thread-0 ready get lock
Thread-0 already got lock
Thread-0:递归层级:2
Thread-0 ready get lock
Thread-0 already got lock
Thread-0:递归层级:1
Thread-0 ready release lock
Thread-0 already released lock
Thread-0 ready release lock
Thread-0 already released lock
Thread-0 ready release lock
Thread-0 already released lock
Thread-2 ready get lock
Thread-2 already got lock
Thread-2:递归层级:3
Thread-2 ready get lock
Thread-2 already got lock
Thread-2:递归层级:2
Thread-2 ready get lock
Thread-2 already got lock
Thread-2:递归层级:1
Thread-2 ready release lock
Thread-2 already released lock
Thread-2 ready release lock
Thread-2 already released lock
Thread-2 ready release lock
Thread-2 already released lock
Thread-1 ready get lock
Thread-1 already got lock
Thread-1:递归层级:3
Thread-1 ready get lock
Thread-1 already got lock
Thread-1:递归层级:2
Thread-1 ready get lock
Thread-1 already got lock
Thread-1:递归层级:1
Thread-1 ready release lock
Thread-1 already released lock
Thread-1 ready release lock
Thread-1 already released lock
Thread-1 ready release lock
Thread-1 already released lock

公平和非公平锁
公平:每一个线程都放到队列的队尾,挂到最后一起排队
非公平:新进程可以抢占拿锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值