AQS 启发--自己实现一个ReentrantLock的一部分(独占式非公平锁)

ReentrantLock

什么是ReentrantLock ?
ReentrantLock 中文翻译过来就是可重入锁,也就是同一个线程这个锁是可以重复获取的 ,synchronize关键字就是一个隐式的可重入锁。
ReentrantLock 的实现原理
ReentrantLock 是实现了Lock接口使得它能够作为一个锁被使用,同时他还有一个内部类同步器:Sync ,这个类继承了AQS(AbstractQueuedSynchronizer) 类,然后实现AQS里面的模板方法。
在这里插入图片描述

自己实现一个ReentrantLock

这里我们来实现一个独占式的非公平锁
代码骨架搭建
要实现一个 ReentrantLock 首先的实现Lock接口,如下:


class MyReentrantLock implements Lock{
    /**
     * 加锁方法
     */
    @Override
    public void lock() {

    }

    /**
     * 中断加锁方法
     * @throws InterruptedException
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    /**
     * 尝试加锁
     * @return
     */
    @Override
    public boolean tryLock() {
        return false;
    }

    /**
     * 在规定的时间内 尝试加锁
     * @param time
     * @param unit
     * @return
     * @throws InterruptedException
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {

    }

    /**
     * 线程条件 里面的方法与Object里面的 wait,notify,notifyAll 等方法类似
     * @return
     */
    @Override
    public Condition newCondition() {
        return null;
    }
}

同时还需要有一个基于AQS的同步器
这里我们在上面的类里面写一个内部类来继承AQS 同时重写下面 的三个方法
在这里插入图片描述
到这里这个ReentrantLock 的骨架就已经搭建好了,下面就是实现部分
实现MySync同步器

   /**
     * 自定义的同步器,仅仅实现
     */
    class MySync extends AbstractQueuedSynchronizer {
        /**
         * 尝试获取锁
         * @param acquire
         * @return
         */
        @Override
        protected boolean tryAcquire(int acquire) {
           // System.out.println("加锁");
        //1、获取当前的线程
            Thread thread = Thread.currentThread();
        //2、获取当前的线程状态
            int state = getState() ;
        //3、判断状态是不是为0,如果为0那么就是说明当前锁还未被持有,很有可能有其他线程来获取该锁,那么需要进行CAS操作来设置锁的持有状态
            if(state==0 && compareAndSetState(0,acquire)){
                //获取锁成功,将持有线程设置为当前线程
                setExclusiveOwnerThread(thread);
                return true;
                //由于是独占式锁,那么如果是当前线程持有的锁那么就只需要设置状态+1就好了
                //否则就获取不成功
            }else if(thread==getExclusiveOwnerThread()){
                if(state+acquire>=0){
                    setState(state+acquire);
                }
                return true;
            }
            return false;
        }
        /**
         * 尝试释放锁
         * @param release
         * @return
         */
        @Override
        protected boolean tryRelease(int release) {
            //释放锁的时候有两点需要注意
            // 1、释放锁的时候肯定是只有持有锁的线程才能来释放锁,所以不需要CAS操作
            //2、释放锁的时候只有当状态为0 的时候才算释放完成
            Thread thread = Thread.currentThread();
            if(thread!=getExclusiveOwnerThread()){
               throw new RuntimeException("非法操作");
            }
            int state = getState()-release;
            boolean flag = false;
            //如果状态为0
            if(state==0){
                //将持有线程置空
                setExclusiveOwnerThread(null);
                flag= true;
            }
            //设置线程状态
            setState(state);
            //System.out.println("释放");
            return flag;
        }
        /**
         * 是不是当前线程持有锁
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread()==Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }

lock 接口的实现

/**
     * 加锁方法
     */
    @Override
    public void lock() {
        this.mySync.acquire(1);
    }
    /**
     * 中断加锁方法
     * @throws InterruptedException
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        this.mySync.acquireInterruptibly(1);
    }
    /**
     * 尝试加锁
     * @return
     */
    @Override
    public boolean tryLock() {
        return this.mySync.tryAcquire(1);
    }
    /**
     * 在规定的时间内 尝试加锁
     * @param time
     * @param unit
     * @return
     * @throws InterruptedException
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return this.mySync.tryAcquireNanos(1, unit.toNanos(time));
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        this.mySync.release(1);
    }

    /**
     * 线程条件 里面的方法与Object里面的 wait,notify,notifyAll 等方法类似
     * @return
     */
    @Override
    public Condition newCondition() {
        return this.mySync.newCondition();
    }

到这里自定义的 ReentrantLock(独占式非公平锁) 就实现完成了

下面我们看一下效果

测试

我们写如下一段测试代码来测试是否成功
其中ThreadFactory 是自定义的一个线程工厂,可以不用传入

public class SelfLock {

    public static void main(String[] args) {
        final MyReentrantLock reentrantLock  = new MyReentrantLock();
        final List<Integer> list = new ArrayList<>();
        final CountDownLatch countDownLatch = new CountDownLatch(100);
        final AtomicReference<MyInteger> atomicI = new AtomicReference<MyInteger>(new MyInteger(4999));
        for (int i = 0; i < 5000; i++) {
            list.add(i);
        }
        final MyInteger j = new MyInteger(4999);
        /*定义线程工厂 方便bug回溯追踪*/
        ThreadFactory customThreadfactory = new ThreadFactoryBuilder()
                .setNamePrefix("测试-Thread").setDaemon(false)
                .setPriority(Thread.MAX_PRIORITY).build();
        /*keepAliveTile 线程最大空闲时间 */
        ExecutorService executorService =
                new ThreadPoolExecutor(100, 200, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),customThreadfactory);
        long b = System.currentTimeMillis();
        for(int i=0;i<100 ;i++){
            executorService.execute(() -> {
                        while (true) {
                          //   int j = atomicInteger.getAndDecrement();
                            if (j.getIndex() >= 0) {
                                reentrantLock.lock();
                                System.out.println("线程"+Thread.currentThread().getName()+"====》" +list.get(j.getIndex()));
                                j.setIndex(j.getIndex()-1);
                                reentrantLock.unlock();
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            } else {
                                break;
                            }
                        }
                countDownLatch.countDown();
                    }
            );
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("耗时---->" + (System.currentTimeMillis() - b));
        executorService.shutdown();

    }

}

class MyInteger{
    int index;
    public MyInteger(int i){
        this.index=i;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

测试效果:

在这里插入图片描述
测试成功,没有发生线程不安全的情况

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章