JDKのReentrantLockロックを手動で

事前に考える

まず、ReentrantLockと同期の最大の違いは、同期がオブジェクトのヘッドをロックすることであり、ReentrantLockはロックの購入に似ており、マルチスレッドによるリソースの原子性と可視性の問題を引き起こさないことを明確にします。この点を明らかにすると、実際のロックは実際のロックとそれほど変わりません。実際のロックはドアのロックにすぎないので、上記のロックがここにあることを他のユーザーに伝えます。唯一の違いは、プログラムロックはロックをロックした人はロックを解除し、実際には他の誰かのロックを保持してロックを解除できます。
ここに画像の説明を挿入

主に使用されているクラス

  • AtomicInteger:主に、このロックの原子性と可視性、および後続の再入可能ロックの状態を保証します。注:揮発性は、リソースの可視性のみを保証できますが、原子性は保証できません
  • スレッド:現在のスレッドがロックを保持している[PS:誰がロックを保持しているか、再入可能なロックはここから後で再入力でき、ロック解除に必要なもの]
  • LinkedBlockingQueue:ロックオブジェクトを取得しなかったコンテナ
  • LockSupport:スレッド状態の切り替え

説明が終わりました!

/**
     * 线程状态定义
     */
    AtomicInteger state = new AtomicInteger();

    /**
     * 那个线程持有锁
     */
    Thread ownerThread = null;

    /**
     * 存放线程的容器
     */
    LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();

このステップは続行するために言うことは何もありません!

public boolean tryLock() {
    
    
        //不用每次都进行CAS操作,如果当期状态为0我直接返回抢锁成功
        if (state.get() == 0) {
    
    
            //CAS抢锁
            if (state.compareAndSet(0, 1)) {
    
    
                //将抢到锁的线程设定为当前锁的持有者
                ownerThread = Thread.currentThread();
                return true;
            }
        } else if (ownerThread == Thread.currentThread()) {
    
    
            System.out.println("重入锁成功!!!!");
            state.set(state.get() + 1);
            return true;
        }
        return false;
    }

ここではCASメカニズムが主に使用されます。変更が成功すると、ロックが取得されたことを証明します。失敗すると、キューに追加されます。再入可能ロックが現在のスレッドである場合、ロックは正常に取得され、状態+1 [PS:ここでの状態+1は主に再入可能ロックになるためには、再入可能ロックの性質上、数回ロックして数回解放する必要があります]

public void lock() {
    
    
        //真公平锁  如果没有!waiters.isEmpty(),在锁的上一个持有者他也会抢
        if (!waiters.isEmpty() || !tryLock()) {
    
    
            //没抢到锁进入等待队列
            waiters.add(Thread.currentThread());
            for (; ; ) {
    
    
                if (tryLock()) {
    
    
                    //移除并且返回队列头部
                    waiters.poll();
                    return;
                } else {
    
    
                    //没抢到   进入阻塞(WAITING)
                    LockSupport.park();
                }
            }
        }
    }

ロックを保持しているスレッドがない場合は、直接戻ります。ある場合は、キューに追加してブロックします[PS:もちろん、一部の類人猿は、LinkedBlockingQueueの使用はすでに公平なロック(先入れ先出し)であると考えていますが、実際には、3つのスレッドがあり、 1人がロックの獲得に成功しました。解放後、1人もロックの獲得に参加しました。つまり、ラインにジャンプします!ここでキューをジャンプすると、一見公平なロックが不公平になります]

public void unlock() {
    
    
        //如果不是当前线程那么不允许释放锁
        if (Thread.currentThread() != ownerThread) {
    
    
            throw new RuntimeException("不是你的别乱动,你不是锁的持有者");
        }
        //释放锁的过程,每次过来减一
        if (state.decrementAndGet() == 0) {
    
    
            ownerThread = null;
            //获取第一个等待的元素并且通知他开始抢锁了,此时还不能移除
            //在真正抢到锁后才能移除队列
            Thread waiter = waiters.peek();
            if (waiter != null) {
    
    
                LockSupport.unpark(waiter);
            }
        }
    }

ここで、ロックを解放するときは、現在ロックを保持しているスレッドでなければなりません。他のスレッドがロックを解放すると、
PS がめちゃくちゃになります。何か問題がある場合、遠慮なく指摘してください

おすすめ

転載: blog.csdn.net/cj181jie/article/details/108710092