package com.jx.source.juc.aqs;import lombok.Data;import lombok.NoArgsConstructor;import lombok.extern.slf4j.Slf4j;import sun.misc.Unsafe;import java.lang.reflect.Field;import java.util.concurrent.locks.LockSupport;/** * @Description: * @Author: zhangjx * @Date: 2021-08-30 **/@Slf4jpublic class MiniReentrantLock implements Lock{ /** * 0 表示未加锁状态 * >0 表示加锁状态 */ private volatile int state; /** * 当前占有锁的线程 * 独占模式 : 统一时间只有一个线程可以持有锁 ,其它的线程未获取到锁时会被阻塞 */ private Thread exclusiveOwnerThread; /** * 头节点 head 节点对应的线程是占用锁的线程 */ private Node head; /** *尾结点 */ private Node tail; static Unsafe U; /** * state偏移量 */ static long stateOffset; /** * head偏移量 */ static long headOffset; /** * tail偏移量 */ static long tailOffset; /** * 阻塞的线程封装成node节点 放入fifo队列 */ @Data @NoArgsConstructor static final class Node{ /**等待线程*/ Thread thread; /**前置节点*/ Node pre; /**后置节点*/ Node next; public Node(Thread thread) { this.thread = thread; } } static { try { final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); U = (Unsafe) theUnsafe.get(null); stateOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("state")); headOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("head")); tailOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("tail")); } catch (Exception e) { log.error("Unsafe 初始化异常",e); } } protected final boolean compareAndSetHead(Node expectedValue, Node newValue) { return U.compareAndSwapObject(this, headOffset, expectedValue, newValue); } protected final boolean compareAndSetTail(Node expectedValue, Node newValue) { return U.compareAndSwapObject(this, tailOffset, expectedValue, newValue); } protected final boolean compareAndSetState(int expectedValue, int newValue) { return U.compareAndSwapInt(this, stateOffset, expectedValue, newValue); } protected final int getAndIncrementState() { return U.getAndAddInt(this, state, 1); } public void setHead(Node node) { //当前线程已经是获取锁的线程了 this.head = node; node.thread = null; node.pre = null; } public int getState() { return state; } public Node getHead() { return head; } public Node getTail() { return tail; } public Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } /** * 模拟公平锁 */ @Override public void lock() { acquire(1); } @Override public void unLock() { release(1); } private void release(int arg){ if(tryRelease(arg)){ Node h = this.head; if(h.next != null){ unparkThread(h); } } } private void unparkThread(Node node){ Node s = node.next; if(s != null && s.thread != null){ LockSupport.unpark(s.thread); } } /** * 释放锁成功返回true * @return */ private boolean tryRelease(int arg){ int c = getState() - arg; if(getExclusiveOwnerThread() != Thread.currentThread()){ throw new RuntimeException("must get lock"); } //执行到这里不存在并发 只有持有锁的线程能够执行到这里 if(c == 0){ /** * 锁已经完全释放了 * 1、exclusiveOwnerThread设置为空 * 2、state 设置为0 */ this.exclusiveOwnerThread = null; this.state = 0; return true; }else { this.state = c; } return false; } /** * 获取锁成功则返回 否则阻塞 * @param arg */ private void acquire(int arg){ if(!tryAcquire(arg)){ Node node = addWaiter(); acquireQueued(node,arg); } } /** *尝试抢锁失败需要做什么? * 1、将当前线程封装成Node加入队列 * 2、需要将当前线程park掉 使当前线程处于挂起状态 * 唤醒后需要做什么? * 1、检查当前Node节点是否为head.next节点(head.next节点拥有抢占权限 其他的线程没有抢占权限) * 2、抢占 * 成功: 将当前node设置为head,将老的head做出队操作 * 失败:继续park 等待被唤醒 */ private void acquireQueued(Node node,int arg){ for (;;){ Node pre = node.pre; if(pre == head && tryAcquire(arg)){ /** * 说明当前线程竞争锁成功 * 1、设置当前head为node * 2、原始head出队 */ setHead(node); pre.next = node; return; } log.info("当前线程{} 挂起",Thread.currentThread().getName()); //将当前线程挂起 LockSupport.park(); log.info("当前线程{} 唤醒",Thread.currentThread().getName()); } } /** * 尝试获取锁不阻塞线程 * true 抢锁成功 * false 抢锁失败 * @param arg * 返回false情况: * 1、cas失败 * 2、state > 0 */ private boolean tryAcquire(int arg){ if(state == 0){ //当state==0时 不能直接抢锁 公平锁 先来后到 if(!hasQueuedThreads() && compareAndSetState(0,arg)){ this.exclusiveOwnerThread = Thread.currentThread(); return true; } }else if(Thread.currentThread() == this.exclusiveOwnerThread){ //锁被当前线程占用 重入 int c = getState(); c = c + arg; this.state = c; return true; } return false; } /** * 判断是否有线程等待 * 什么时候返回false * 1、 当前队列是空 * 2、 当期线程为head.next节点线程 head.next在任何时候都有权利竞争锁 * @return */ private boolean hasQueuedThreads(){ Node h = head; Node t = tail; Node s; /** * 条件1: h != t * true 说明当前队列已经有node了 * false * 1、h == t == null 队列中没有node * 2、h == t == head 第一个获取锁失败的线程会为当前持有锁的线程补充创建一个head节点 * 条件2:s = h.next) != null || s.thread != Thread.currentThread() * 前置条件: 队列中有node * 条件2.1 (s = h.next) != null * 避免 enQueue时的并发情况 * 如当前队列已经有节点a head=a,tail=a, 队列 a -> * 线程b cas成功 设置a为b的前驱节点 但是还未将a的后继设置为b head = a,tail = b ,队列 a <- b * 线程c cas成功 设置b为c的前驱节点 head=a,tail=c 队列: a<- b <=> c * * 此时head.next虽然为null但是实际上head.next已经被预订了 * * 条件2.2 s.thread != Thread.currentThread() * true 当前线程是head.next节点 * false 当前线程不是head.next节点 * * 如果是 a<=>b b为当前线程节点 返回false 此时当前线程有抢锁资格 * 如果是 a <- b<=>c c为当前线程节点 c没有抢锁资格 */ return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } /** * 当前线程入队 * 返回当前线程对应的Node节点 * 入队流程: * 队列已经有等待节点 * 1、找到newNode的前置节点 pre * 2、更新newNode.pre = pre * 3、CAS更新tail为newNode * 4、更新pre.next= newNode * * @return */ private Node addWaiter(){ Node newNode = new Node(Thread.currentThread()); //此处不要用tail,用pre保存当前tail,tail可能被修改 Node pre = tail; if(pre!= null){ newNode.pre = pre; if(compareAndSetTail(pre,newNode)){ pre.next= newNode; return newNode; } } /** * 执行到这里的情况 * 1、tail==null * 2、CAS设置当前newNode为tail失败 */ enQueue(newNode); return newNode; } /** * 自旋入队 只有成功后才返回 * 1、tail==null 空队列 * 2、CAS设置当前newNode为tail失败 * @param node * @return */ private void enQueue(Node node){ for (;;){ /** * 1、队列是空 * 说明当前线程是第一个抢锁失败的线程 不然队列应该有一个节点,即当前持有锁线程节点,而当前持有锁的线程由于没有抢锁失败,队列中没有当前持有锁的线程的节点 * 所以当前线程需要为当前持有锁线程建立节点 head节点任何时候都代表占有锁线程节点 */ if(compareAndSetHead(null,node)){ tail = head; }else { //说明当前队列已经有node了,需要追加node Node pre = tail; if(pre!= null){ node.pre = pre; if(compareAndSetTail(pre,node)){ pre.next= node; return; } } } } }}