【并发专题】手写MyReentantLock

分析

ReentantLock的特点如下:

  1. 首先是继承自AQS的
  2. 可中断
  3. 可以设置超时时间
  4. 可以切换公平锁/非公平锁
  5. 支持多个条件变量
  6. 支持可重入

事实上,上面的很多东西AQS已经帮忙实现了,所以想要复刻一个不是很难。仔细观察一下源码,我们需要重写的接口只有以下几个:

  1. 新建一个自己的MyReentrantLock类,实现了Lock接口
  2. MyReentrantLock里面,新建一个NonfairSync类,继承自AbstractQueuedSynchronizer
  3. NonfairSync里面需要实现如下接口:

void lock();
boolean tryAcquire();
boolean tryRelease();

至于为什么需要实现这三个接口,看如下注释:
【并发专题】手写MyReentantLock_第1张图片
总的来说:实现lock()是因为我们要实现可重入的话,需要自己写逻辑补充;
实现tryAcquire(),则是因为提供一种机制,让任务尽量可能在进入阻塞队列之前,能获取到锁。因为,进了阻塞队列之后可能会反复阻塞和解除阻塞(经历上下文切换),这个代价是昂贵的;
实现tryRelease(),则是因为这个方法是【释放锁】的核心方法。想要实现可重入的逻辑就得维护这个方法。

源码

为了方便,这里只是简单实现了一个非公平锁的代码。

public class MyReentrantLock implements Lock {

    /**
     * 锁实例
     */
    private NonfairSync sync;

    /**
     * 构造放啊
     */
    public MyReentrantLock() {
        sync = new NonfairSync();
    }

    @Override
    public void lock() {
        sync.lock();
    }

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

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

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

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

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

    /**
     * 非公平锁的实现方式
     */
    public static final class NonfairSync extends AbstractQueuedSynchronizer {

        /**
         * 非公平锁,上锁方法
         */
        public void lock() {

            // CAS操作锁
            boolean result = compareAndSetState(0, 1);
            if (result) {

                // 设置成功,则修改独占状态
                setExclusiveOwnerThread(Thread.currentThread());
            } else {

                // 设置不成功,则准备入等待队列
                acquire(1);
            }
        }

        /**
         * 实现AQS对tryAcquire的方法
         *
         * 

* 以下是AQS的解释: * 以独占模式获取,忽略中断。通过调用至少一次tryAcquire实现,成功时返回。 * 否则,线程将被排队,可能会反复阻塞和解除阻塞,调用tryAcquire直到成功。 * 这个方法可以用来实现方法Lock.lock。 *

*/
@Override protected boolean tryAcquire(int acquires) { return doTryAcquire(acquires); } /** * 实现AQS的tryRelease方法 * *

* 通用场景 * 术语库 * 尝试将状态设置为在独占模式下反映释放。 * 此方法总是由执行释放的线程调用。 * 默认实现抛出UnsupportedOperationException。 * 参数: * Arg -释放参数。该值始终是传递给释放方法的值,或者是进入条件等待时的当前状态值。否则该值是不解释的,可以表示您喜欢的任何内容。 * 返回: * 如果该对象现在处于完全释放状态,则为True,以便任何等待的线程都可以尝试获取;否则为假。 * 抛出: * IllegalMonitorStateException -如果释放会使同步器处于非法状态。此异常必须以一致的方式抛出,才能使同步正常工作。 * UnsupportedOperationException -如果不支持独占模式 *

*/
@Override protected boolean tryRelease(int releases) { final Thread thread = Thread.currentThread(); if (thread != getExclusiveOwnerThread()) { throw new IllegalMonitorStateException(); } int state = getState(); int newState = state - releases; // 接口要求,完全释放则true,反之false boolean fullyRelease = false; if (newState == 0) { fullyRelease = true; setExclusiveOwnerThread(null); } setState(newState); return fullyRelease; } private ConditionObject newCondition() { return new ConditionObject(); } /** * 实现非公平模式下的tryAcquire */ private boolean doTryAcquire(int acquires) { final Thread currentThread = Thread.currentThread(); int state = getState(); if (state == 0) { // 再次竞争一下 boolean result = compareAndSetState(0, acquires); if (result) { setExclusiveOwnerThread(currentThread); return true; } } else { // 判断是否为可重入 Thread exclusiveOwnerThread = getExclusiveOwnerThread(); if (exclusiveOwnerThread == currentThread) { // 做可重入的逻辑 return doReentrantLock(state + acquires); } } return false; } private boolean doReentrantLock(int newState) { if (newState < 0) { throw new Error("可重入次数已达上限"); } setState(newState); return true; } } }

使用示例

public class MyReentrantLockTest {

    // 票数
    public static int tickets = 8;

    // 总人数
    public static final int PERSONS = 10;

    public static final Lock LOCK = new MyReentrantLock();


    public static void main(String[] args) {

        for (int i = 0; i < PERSONS; i++) {
            new Thread(() -> {
                buyTicket();
            }).start();
        }
    }

    public static void main1(String[] args) {
        MyReentrantLock lock = new MyReentrantLock();
        lock.lock();
        try {
            System.out.println("试试看");
            lock.lock();
            try {
                System.out.println("可重入了");
            } finally {
                lock.unlock();
            }
        } finally {
            lock.unlock();
        }
    }


    public static void buyTicket() {
        // 获取锁
        LOCK.lock();
        try {
            Thread.sleep(1000);

            if(tickets > 0) {
                System.out.println("我是" + Thread.currentThread().getName() + ",我来抢第【" + tickets-- + "】张票");
            } else {
                System.out.println("我是" + Thread.currentThread().getName() + ",票卖完了我没抢到");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放说
            LOCK.unlock();
        }
    }

//    系统输出如下:
//    我是Thread-0,我来抢第【8】张票
//    我是Thread-1,我来抢第【7】张票
//    我是Thread-2,我来抢第【6】张票
//    我是Thread-3,我来抢第【5】张票
//    我是Thread-4,我来抢第【4】张票
//    我是Thread-5,我来抢第【3】张票
//    我是Thread-9,我来抢第【2】张票
//    我是Thread-7,我来抢第【1】张票
//    我是Thread-8,票卖完了我没抢到
//    我是Thread-6,票卖完了我没抢到
}

你可能感兴趣的:(tuling学院学习笔记,java)