基于reentrantlock,引用其思想和部分代码进行整合,并进行注释
/*** Created by zhaohui on 2021/5/1.*/public interface Lock {void lock();void unlock();}
package com.example.zhaohui.lock;import org.springframework.aop.ThrowsAdvice;import sun.misc.Unsafe;import java.lang.reflect.Field;import java.util.concurrent.locks.LockSupport;/*** Created by zhaohui on 2021/5/1.*/public class MyLock implements Lock {private volatile int state;private volatile Thread exclusiveOwnerThread;private Node head;private Node tail;static final class Node{Node next;Node prev;Thread thread;Node(Thread t){this.thread = t;}Node(){};}/*** 抢占时如果锁被占用,则阻塞调用者的线程,直至抢占成功* 模拟先来后到的公平锁。* 1、 第一次进来发现state = 0 抢锁。* 2、state>0 ,将当前线程加入到队列里*/@Overridepublic void lock() {acquire(1);}//尝试获取,成功则返回//失败则阻塞private void acquire(int arg) {// 抢占失败了,将他们放到阻塞队列里然后挂起// 在被唤醒时,要看看当前线程是否是head.next// head.next节点是唯一拥有抢占权的线程// 抢占成功将当前node设为head,并出队老head// 失败继续挂起等待被唤醒/*** 添加到阻塞队列 -> addWaiter()* 竞争资源 -> acquireQueued()*/if(!tryAcquire(arg)){Node node = addWaiter();acquireQueued(node,arg);}}// 尝试获取,不阻塞线程private boolean tryAcquire(int arg) {if(state == 0){// state=0时不能直接拿锁,要看看前面有没有等待的线程if(!hasQueuedPredecessor() && compareAndSetState(0,arg)){//抢锁成功exclusiveOwnerThread = Thread.currentThread();return true;}// 代码至此,当前锁是被占用的,看看是不是自己占用的,因为可重入}else if(Thread.currentThread() == exclusiveOwnerThread){state += arg;}// cas失败 stat>0且当前线程不是独占线程,需要将这些加入到阻塞队列里return false;}// true -> 有等待线程// false -> 无等待线程private boolean hasQueuedPredecessor() {// state为0时,在抢占前先看看有没有线程在等待// 返回false的情况,当队列为null;当前线程为head.next,head.next有权利去获取锁,及当前线程就是后置节点Node h = head;Node t = tail;Node s;/*** h != t* 成立:说明队列已经有node存在* 不成立:1、 h == t == null 2、h == t == head(第一个抢占失败的线程会为当前线程持有的线程创建一个空的node节点,后head和tail都指向它)* (s = h.next) == null || s.thread != Thread.currentThread()* 首先可肯定 条件1已经成立,队列已经存在* (s = h.next) == null 很极端,因为基于第一个条件下,几乎不会为空,即几乎总是返回true* s.thread != Thread.currentThread() 到此则说明 (s = h.next) != null,如果head的后置节点不是自己,即无权*/return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());}// addWaiter保证入队必须成功private Node addWaiter(){Node newNode = new Node(Thread.currentThread());Node pred = tail;if(pred != null){if(compareAndSetTail(pred,newNode)){pred.next = newNode;return newNode;}}// 到此,尾节点为空,cas失败,则循环保证其入队enq(newNode);return newNode;}private void enq(Node newNode) {for(;;){//1.队列为空,当前线程是第一个抢占失败的线程//当前持有锁的线程并没有设置过任何node,所以作为该线程的第一个后继节点则需要为它补充一个node节点//head任何时候都表示持有锁的线程if(tail == null){//补充node,也不要设置占用线程if(compareAndSetHead(new Node())){head = tail;}}else {Node pred = tail;if(pred != null){//入队成功退出即可if(compareAndSetTail(pred,newNode)){pred.next = newNode;return;}}}}}/*** 获取到锁再退出自旋* 当前线程是head的next节点才能有权限获取锁* @param node*/private void acquireQueued(Node node,int arg){for (;;){Node pred = node.prev;// 此条件成立,说明当前node有权限去抢占,去试试if(pred == head && tryAcquire(arg)){//抢占成功,将此节点设置为head 并将原head节点出队setHead(node);pred.next = null; //help gcreturn;}//如果当前线程不是head.next,或者并发下抢占失败了 需要挂起System.out.println("线程:" + Thread.currentThread().getName() + "挂起");LockSupport.park();System.out.println("线程:" + Thread.currentThread().getName() + "唤醒");}}@Overridepublic void unlock() {release(1);}private void release(int arg){// 释放锁了 可以去看看队列里是否有等待的线程进行唤醒if(tryRelease(arg)){Node h = head;//看看是否有等待线程 h.next == null 则没有if(h.next != null){//唤醒h.nextunParkSuccessor(h);}}}private void unParkSuccessor(Node node){Node s = node.next;if(s != null && s.thread != null){LockSupport.unpark(s.thread);}}// state 减为0 返回truepublic boolean tryRelease(int arg){int c = state - arg;if(exclusiveOwnerThread != Thread.currentThread()){throw new Error("无权限");}if(c == 0){exclusiveOwnerThread = null;state = c;return true;}state = c;return false;}public Node getHead() {return head;}public void setHead(Node node) {this.head = node;//当前node已经是获取锁成功的线程了node.thread = null;// 当前node成为头结点,则需要将原来前置引用去掉node.prev = null;}public Node getTail() {return tail;}public void setTail(Node tail) {this.tail = tail;}private static final Unsafe unsafe;private static final long stateOffset;private static final long headOffset;private static final long tailOffset;static {try{Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);stateOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("state"));headOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("head"));tailOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("tail"));} catch (Exception e) {throw new Error(e);}}private final boolean compareAndSetHead(Node head){return unsafe.compareAndSwapObject(this,headOffset,null,head);}private final boolean compareAndSetTail(Node expect,Node tail){return unsafe.compareAndSwapObject(this,tailOffset,expect,tail);}private final boolean compareAndSetState(int expect,int update){return unsafe.compareAndSwapObject(this,stateOffset,expect,update);}}
