The ReentrantLock lock of JDK by hand

Pre-thinking

First of all, make it clear that the biggest difference between ReentrantLock and synchronized is that synchronized is to lock the head of the object, and ReentrantLock is similar to buying a lock, and we don’t want to cause resource atomicity and visibility problems due to multithreading. When this point is made clear, our locks are actually not much different from those in life. The locks in life are nothing more than a lock on the door, so we tell others that the above locks are here. The only difference is that the program lock must be The person who locked the lock will unlock it, and in life we ​​can hold someone else's lock to unlock it.
Insert picture description here

Mainly used classes

  • AtomicInteger: Mainly guarantees the atomicity and visibility of this lock, as well as the state of the subsequent reentrant locks. Note: Volatile can only guarantee the visibility of resources, but not atomicity
  • Thread: The current thread holds the lock [PS: who holds the lock, reentrant locks can be re-entered from here to later, and what is needed for unlocking]
  • LinkedBlockingQueue: The container that did not grab the lock object
  • LockSupport: Switch thread state

The explanation is over! ! ! !

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

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

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

This step has nothing to say to continue! !

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;
    }

The CAS mechanism is mainly used here. If the modification is successful, it proves that the lock has been grabbed. If it fails, it will be added to the queue. If the reentrant lock is the current thread, the lock is successfully acquired, and in the state +1 [PS: The state +1 here is mainly In order to be reentrant locks, the nature of reentrant locks requires you to lock several times and release several times]

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

If there is no thread holding the lock, return directly. If there is, add it to the queue and block [PS: Of course, some apes think that using LinkedBlockingQueue is already a fair lock (first in, first out), in fact, it is not like: there are three threads, 1 successfully grabbed the lock. After the release, 1 also participated in the lock grab, that is, jump in the line! ! Jumping the queue here will cause the seemingly fair lock to become unfair]

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);
            }
        }
    }

Here, when we release the lock, it must be the thread currently holding the lock. If other threads release the lock, it will mess up the
PS: If there is something wrong, please feel free to point out

Guess you like

Origin blog.csdn.net/cj181jie/article/details/108710092