ReentrantLock源码分析

目录

1:reentrantLock使用

1.1  构造lock的test模型

package com.saytoyou.com.lock;

import java.util.concurrent.locks.ReentrantLock;

public class LockTest extends Thread {

    private int a = 1;

    private ReentrantLock lock;

    public LockTest(ReentrantLock lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        lock.lock();
        try {
            a = a + 1;
            System.out.println(Thread.currentThread().getName()+"a===="+a);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}
View Code

1.2:使用main方法进行测试

package com.saytoyou.com.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTestTwo {

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();

        LockTest lockTest = new LockTest(lock);

        for (int i = 1;i<=100;i++){
            new Thread(lockTest).start();
        }

    }

}
View Code

 

2:开始源码分析

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

构造reentrantLock模型,可以通过构造函数构造公平锁或者非公平锁

2.1 分析公平锁和非公平锁

非公平锁NoneFairSync方法分析

 static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

lock的时候直接尝试setState的值,如果设置成功表示获取到锁,设置独占线程为当前线程,否则进行第二部

2:第二部acquire尝试获取锁,源码如下:

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { 重入方法,state的值叠加
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

其实acquire主要就是直接获取锁,没有判断等待队列是否有等待线程,和公平锁的区别,

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

acquireQeued方法就不介绍了,AQS源码有分析

2.2  公平锁源码分析

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&  先判断是否有等待队列线程
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

公平锁先判断是否有等待队列线程,如果有等待队列直接返回false,加入等待队列FIFO

如果没有等待队列才开始尝试获取资源,设置state的值,和非公平锁的不同之处就在这

3:unLock源码分析

  public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

首先进行tryRelease释放state的值,如果释放成功,进行线程唤醒工作,注意只有当前获取到锁的线程指向head节点,所以释放传入头节点即可

tryRelease源码如下:

 protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

当前的state减去1,如果不是当前线程调用unLock则直接报错,如果等于0说名释放成功,则线程直接重置

3.1:unparksuccessor()方法介绍

  private void unparkSuccessor(Node node) {
      
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

不懂的看一看AQS源码,基本就是拿到节点,找到子啊一个节点,进行unpark话逆行,如果状态不正确,就从后往前找一个正确的节点进行释放

 

posted @ 2022-04-14 15:19  xzlnuli  阅读(35)  评论(0编辑  收藏  举报