ReentrantLock 源码解读

ReentrantLock(默认非公平锁): 可重入锁, 公平所, 非公平锁

lock(公平锁)

public class ReentrantLockDemo {
    try {
        // 公平锁
        ReentrantLock rl = new ReentrantLock(true);
        rl.lock();
     rl.lock();
        // 能够更请清楚看整个执行流程
		TimeUnit.SECONDS.sleep(60);
        new Thread(() -> {
          rl.lock();
        }, "aaa").start();
        TimeUnit.SECONDS.sleep(60);
        new Thread(() -> {
          rl.lock();
     }, "bbb").start();
    } catch (Exception e){
     e.printStackTrace();
    }	
}
public class ReentrantLock implements Lock, java.io.Serializable { 
  	// 初始化
	public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  
  	// 将 Sync 和 AbstractQueuedSynchronizer 的代码合并了一起说明
  	static final class FairSync extends Sync extends AbstractQueuedSynchronizer {
      	// 重入次数
      	private volatile int state;
      	// 当前节点超时或者终端, 该节点被取消, 节点永远不会改变状态, 并且取消该节点的线程永远不会再次阻塞
      	static final int CANCELLED =  1;
      	// 等待状态值, 后续线程需要暂停
      	static final int SIGNAL = -1;
      	// 表示线程处于等待状态, 当前线程处于条件队列行 Condition
      	static final int CONDITION = -2;
      	// 表示下一个对象的默认状态值应该无条件传递下去
      	static final int PROPAGATE = -3;
      	// 初始化, 用来做线程获取锁的判断
      	private static final Unsafe unsafe = Unsafe.getUnsafe();
     	// 
      	final void lock() {
            acquire(1);
        }
      	public final void acquire(int arg) {
          	// !tryAcquire(arg) 第一次进来, 为true 
          	// 当之前任务没有完成, 后面又有任务来获取锁, 
          	// acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 添加到队列中
        	if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            	selfInterrupt();
    	}
      	// 尝试获取锁
      	protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
          	// 第一次默认值为 0
            int c = getState();
            if (c == 0) {
              	// 第一个任务, hasQueuedPredecessors() 返回false
              	// compareAndSetState(0, acquires)) 成功获取锁, 并改变 state 值为 1
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    // 表示获取到了锁
                    return true;
                }
            }
          	// 当希望获取锁的任务为同一个时(在 unlock() 未执行), 也可以获取锁(可重入)
            else if (current == getExclusiveOwnerThread()) {
              	// 记录被重入的次数
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
             return true;
            }
         // 没有获取锁, 需要将当前任务添加到等待队列中
            return false;
        }
        // 将等待任务添加到 AQS 队列
        private Node addWaiter(Node mode) {// mode 为当前来获取锁的线程
            Node node = new Node(Thread.currentThread(), mode);
            // Try the fast path of enq; backup to full enq on failure
            Node pred = tail;
            if (pred != null) {
                node.prev = pred;
                // 设置尾部的元素, 将当前来获取锁的线程添加到队尾
                if (compareAndSetTail(pred, node)) {
                  	// 上个元素的 next 指向当前获取锁的线程
                    pred.next = node;
                    return node;
                }
            }
          	// 在锁被占用, 后面第一个线程进入, 初始化 node
            enq(node);
            return node;
    	}
        // 初始化 queue 中第一个 node
      	// Node t = tail; tail = head; node.prev = t; t.next = node; 循环指引
        private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) { // Must initialize
                  	// 初始化头节点, node 的 next 才是真正指向当前来获取的线程,
                  	// 而 waitStatus 记录的也是 next 的状态值
                  	// 在 unlock 中可以发现, 每次唤醒的都是 node 的 next,而且 waitStatus 却是更具当前node 的 waitStatus 来判断
                    if (compareAndSetHead(new Node()))
                      	// head = new Node();
                        tail = head;
                } else {
                    // 实际添加元素, node 记录的为当前线程
                    node.prev = t;
                  	// 第二个获取锁的线程在队列中, 既是头节点也是尾节点(在后面线程添加进入队列时, 由于循环引用)
                    if (compareAndSetTail(t, node)) {
                        t.next = node;
                        return t;
                    }
                }
            }
        }
      	// 入队列, 并将当前线程的 prev 的状态修改为 SIGNAL
        final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;// 标记是否获取锁
            try {
              	// 标记线程是否被中断过
                boolean interrupted = false;
              	// 从队尾开始往前, 尝试去获取锁
                for (;;) {
                  	// 当前节点的前置节点
                    final Node p = node.predecessor();
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        // 检查当前线程是否中断过
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
      	}
      	// 返回前个节点
      	final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }
      	
      	// 判断当前节点获取锁失败后是否需要挂起
      	// node 当前线程, pred 当前线程的前置节点
        private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
          	// 当前置节点状态和当前线程状态一致时(等待), 当前线程需要挂起
            int ws = pred.waitStatus;
            if (ws == Node.SIGNAL)
                
                return true;
            if (ws > 0) {
                // 如果前置节点为 cancel 时
                do {
                  	// 从队尾遍历, 寻找第一个不为 cancel 的线程作为当前线程的新的前置节点
                    node.prev = pred = pred.prev;
                } while (pred.waitStatus > 0);
                pred.next = node;
            } else {
                // waitStatus must be 0 or PROPAGATE.
              	// 当前节点的前置节点的状态的改变
                compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
            }
            return false;
      	}
      	// 取消正在进行的尝试获取
        private void cancelAcquire(Node node) {
            // Ignore if node doesn't exist
            if (node == null)
                return;

            node.thread = null;

            // Skip cancelled predecessors
            Node pred = node.prev;
          	// 重新指向新的前置节点
            while (pred.waitStatus > 0)
                node.prev = pred = pred.prev;

            Node predNext = pred.next;

            node.waitStatus = Node.CANCELLED;

            // If we are the tail, remove ourselves.
          	// 如果当前线程为尾部节点, 则 next 为null
            if (node == tail && compareAndSetTail(node, pred)) {
                compareAndSetNext(pred, predNext, null);
            } else {
                // If successor needs signal, try to set pred's next-link
                // so it will get one. Otherwise wake it up to propagate.
                int ws;
              	// 如果不为头部节点, 并且状态为 signal, 设置前置节点状态为 signal
                if (pred != head &&
                    ((ws = pred.waitStatus) == Node.SIGNAL ||
                     (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                    pred.thread != null) {
                    Node next = node.next;
                    if (next != null && next.waitStatus <= 0)
                        compareAndSetNext(pred, predNext, next);
                } else {
                    unparkSuccessor(node);
                }

                node.next = node; // help GC
            }
      	}
    }
}

lock(非公平锁)

非公平锁流程:

① compareAndSetState(0, 1) 判断是否可以获取锁, 成功获取锁, 并设置为独占锁,

② 如果失败, 会再次尝试去获取锁, 在再次获取锁的过程中, 如果前面线程释放了锁, 这会导致前面排队的线程继续排队, 而后到线程却获取到了锁(非公平).

③ 如果失败,则进入等待队列

public class ReentrantLockDemo {
    try {
        // 公平锁
        ReentrantLock rl = new ReentrantLock(false);
        rl.lock();
     rl.lock();
        // 能够更请清楚看整个执行流程
		TimeUnit.SECONDS.sleep(60);
        new Thread(() -> {
          rl.lock();
        }, "aaa").start();
        TimeUnit.SECONDS.sleep(60);
        new Thread(() -> {
          rl.lock();
     }, "bbb").start();
    } catch (Exception e){
     e.printStackTrace();
    }	
}
 static final class NonfairSync extends Sync extends AbstractQueuedSynchronizer {
   	final void lock() {
      	// 非公平锁, 直接去获取锁
      	if (compareAndSetState(0, 1))
        	setExclusiveOwnerThread(Thread.currentThread());
      	else
          	// 失败, 添加到队列, 
          	// 再次尝试去获取锁, “非公平”即体现在这里,如果占用锁的线程刚释放锁,state置为0,而排队等待锁的线程还未唤醒时,新来的线程就直接抢占了该锁,那么就“插队”了
          	//后面逻辑和公平锁一致
        	acquire(1);
    }
 }

unlock

   	public static void main(String[] args) {  
    	ReentrantLock rl = new ReentrantLock(true);
        rl.lock();
        rl.lock();
        TimeUnit.SECONDS.sleep(20);
        new Thread(() -> {
          rl.lock();
          System.out.println(Thread.currentThread().getName());
        }, "aaa").start();
        TimeUnit.SECONDS.sleep(5);
        rl.unlock();
    }
public void unlock() {
        sync.release(1);
    }
	
	// 是否成功释放锁
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

    protected final boolean tryRelease(int releases) {
      	// getState 获取被重入次数
        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;
    }

	private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
		// 释放的 next 节点, 前面 lock 有说明为啥是 next
        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);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值