【同時トピック】手書きMyReentantLock

分析する

ReentantLockの特徴は以下のとおりです。

  1. 1 つ目は AQS から継承されます
  2. 中断可能
  3. タイムアウトを設定できる
  4. フェアロック/アンフェアロックを切り替え可能
  5. 複数の条件変数のサポート
  6. リエントラント

実際、AQS は上記の多くの実現に貢献しているため、再現することは難しくありません。ソース コードを詳しく見てみると、書き直す必要があるインターフェイスは次のとおりです。

  1. インターフェースMyReentrantLockを実装する独自の新しいクラスを作成します。Lock
  2. 内に、を継承するMyReentrantLock新しいクラスを作成します。NonfairSyncAbstractQueuedSynchronizer
  3. その中でNonfairSync、次のインターフェイスを実装する必要があります。

ボイドロック();
ブール値 tryAcquire();
ブール値 tryRelease();

これら 3 つのインターフェイスを実装する必要がある理由については、次の注記を参照してください:
ここに画像の説明を挿入
一般に: 実装は、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的方法
         *
         * <p>
         * 以下是AQS的解释:
         * 以独占模式获取,忽略中断。通过调用至少一次tryAcquire实现,成功时返回。
         * 否则,线程将被排队,可能会反复阻塞和解除阻塞,调用tryAcquire直到成功。
         * 这个方法可以用来实现方法Lock.lock。
         * </p>
         */
        @Override
        protected boolean tryAcquire(int acquires) {
    
    
            return doTryAcquire(acquires);
        }

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

Supongo que te gusta

Origin blog.csdn.net/qq_32681589/article/details/132042879
Recomendado
Clasificación