并发编程-使用AbstractQueuedSynchronizer(AQS)实现一个自己的锁

简单分析下AQS

AQS是一个抽象类,在设计时使用了模板设计模式,也就是我们只需要实现几个必须实现的方法,其他方法都已经利用模板设计模式给我们封装好了。

我们可以简单找个方法看一下:

如果只是简单的实现一把独享锁,不涉及到读写锁只需要实现tryAcquire,tryRelease,isHeldExclusively这三个方法以及提供一个newCondition方法即可。

模仿ReentrantLock实现一把自己的锁

ReentrantLock实现了lock接口,使用了一个内部类(当然分公平非公平其实不止一个哈)继承了抽象类AQS以这种形式实现了可重入锁。大家可以自己看下源码,这里就不截图了,直接上代码,代码有详细注释

package cn.bikan8;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;


/**
 * @Author 小浩
 * @Date 2020/6/12 15:16
 * @Version 1.0
 **/
public class MyLock implements Lock {
    private  static class Syn extends AbstractQueuedSynchronizer{
        /**
         * 判读当前锁是否被占用
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return  getState() ==1;
        }

        /**
         *拿锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
           if (compareAndSetState(0,1)){
//             设置当前拥有独占访问权限的线程 也就是设置锁被哪个线程拿了
               setExclusiveOwnerThread(Thread.currentThread());
               return true;
           }

           return false;
        }

        /**
         * 释放锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryRelease(int arg) {
            try {
//              这里只有拿到锁的线程才需要释放,我们做的是独占锁所以不会涉及到并发
                setState(0);
                return true;
            }catch (Exception e){
                return false;
            }
        }

        /**
         * 如果需要用到await和sing的时候需要用到
         * @return
         */
        Condition newCondition(){
            return  new ConditionObject();
        }



    }

    private static Syn syn = new Syn();
    @Override
    public void lock() {
        syn.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
         syn.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return syn.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return syn.tryAcquireNanos(1,unit.toNanos(time));
    }

    @Override
    public void unlock() {
        syn.release(1);
    }

    @Override
    public Condition newCondition() {
        return syn.newCondition();
    }
}

 

测试

package cn.bikan8;

/**
 * @Author 小浩
 * @Date 2020/6/16 12:38
 * @Version 1.0
 **/
public class Work implements  Runnable {
    MyLock myLock = new MyLock();
    private int sum =0;
    @Override
    public void run() {
        myLock.lock();
        try {
            for (int i =0;i<10000;i++){
                sum =sum+i;
            }
            for (int i =0;i<10000;i++){
                sum =sum-i;
            }
            System.out.println(sum);
        }finally {
            myLock.unlock();
        }

    }

    public static void main(String[] args) {
        Work work = new Work();
        for (int i =0;i<5;i++){
            new Thread(work).start();
        }
    }
}

 

不用锁很显然结果是线程不安全的

使用锁

 

© 版权声明
THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发