基于reentrantlock,引用其思想和部分代码进行整合,并进行注释

    1. /**
    2. * Created by zhaohui on 2021/5/1.
    3. */
    4. public interface Lock {
    5. void lock();
    6. void unlock();
    7. }
    1. package com.example.zhaohui.lock;
    2. import org.springframework.aop.ThrowsAdvice;
    3. import sun.misc.Unsafe;
    4. import java.lang.reflect.Field;
    5. import java.util.concurrent.locks.LockSupport;
    6. /**
    7. * Created by zhaohui on 2021/5/1.
    8. */
    9. public class MyLock implements Lock {
    10. private volatile int state;
    11. private volatile Thread exclusiveOwnerThread;
    12. private Node head;
    13. private Node tail;
    14. static final class Node{
    15. Node next;
    16. Node prev;
    17. Thread thread;
    18. Node(Thread t){
    19. this.thread = t;
    20. }
    21. Node(){};
    22. }
    23. /**
    24. * 抢占时如果锁被占用,则阻塞调用者的线程,直至抢占成功
    25. * 模拟先来后到的公平锁。
    26. * 1、 第一次进来发现state = 0 抢锁。
    27. * 2、state>0 ,将当前线程加入到队列里
    28. */
    29. @Override
    30. public void lock() {
    31. acquire(1);
    32. }
    33. //尝试获取,成功则返回
    34. //失败则阻塞
    35. private void acquire(int arg) {
    36. // 抢占失败了,将他们放到阻塞队列里然后挂起
    37. // 在被唤醒时,要看看当前线程是否是head.next
    38. // head.next节点是唯一拥有抢占权的线程
    39. // 抢占成功将当前node设为head,并出队老head
    40. // 失败继续挂起等待被唤醒
    41. /**
    42. * 添加到阻塞队列 -> addWaiter()
    43. * 竞争资源 -> acquireQueued()
    44. */
    45. if(!tryAcquire(arg)){
    46. Node node = addWaiter();
    47. acquireQueued(node,arg);
    48. }
    49. }
    50. // 尝试获取,不阻塞线程
    51. private boolean tryAcquire(int arg) {
    52. if(state == 0){
    53. // state=0时不能直接拿锁,要看看前面有没有等待的线程
    54. if(!hasQueuedPredecessor() && compareAndSetState(0,arg)){
    55. //抢锁成功
    56. exclusiveOwnerThread = Thread.currentThread();
    57. return true;
    58. }
    59. // 代码至此,当前锁是被占用的,看看是不是自己占用的,因为可重入
    60. }else if(Thread.currentThread() == exclusiveOwnerThread){
    61. state += arg;
    62. }
    63. // cas失败 stat>0且当前线程不是独占线程,需要将这些加入到阻塞队列里
    64. return false;
    65. }
    66. // true -> 有等待线程
    67. // false -> 无等待线程
    68. private boolean hasQueuedPredecessor() {
    69. // state为0时,在抢占前先看看有没有线程在等待
    70. // 返回false的情况,当队列为null;当前线程为head.next,head.next有权利去获取锁,及当前线程就是后置节点
    71. Node h = head;
    72. Node t = tail;
    73. Node s;
    74. /**
    75. * h != t
    76. * 成立:说明队列已经有node存在
    77. * 不成立:1、 h == t == null 2、h == t == head(第一个抢占失败的线程会为当前线程持有的线程创建一个空的node节点,后head和tail都指向它)
    78. * (s = h.next) == null || s.thread != Thread.currentThread()
    79. * 首先可肯定 条件1已经成立,队列已经存在
    80. * (s = h.next) == null 很极端,因为基于第一个条件下,几乎不会为空,即几乎总是返回true
    81. * s.thread != Thread.currentThread() 到此则说明 (s = h.next) != null,如果head的后置节点不是自己,即无权
    82. */
    83. return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
    84. }
    85. // addWaiter保证入队必须成功
    86. private Node addWaiter(){
    87. Node newNode = new Node(Thread.currentThread());
    88. Node pred = tail;
    89. if(pred != null){
    90. if(compareAndSetTail(pred,newNode)){
    91. pred.next = newNode;
    92. return newNode;
    93. }
    94. }
    95. // 到此,尾节点为空,cas失败,则循环保证其入队
    96. enq(newNode);
    97. return newNode;
    98. }
    99. private void enq(Node newNode) {
    100. for(;;){
    101. //1.队列为空,当前线程是第一个抢占失败的线程
    102. //当前持有锁的线程并没有设置过任何node,所以作为该线程的第一个后继节点则需要为它补充一个node节点
    103. //head任何时候都表示持有锁的线程
    104. if(tail == null){
    105. //补充node,也不要设置占用线程
    106. if(compareAndSetHead(new Node())){
    107. head = tail;
    108. }
    109. }else {
    110. Node pred = tail;
    111. if(pred != null){
    112. //入队成功退出即可
    113. if(compareAndSetTail(pred,newNode)){
    114. pred.next = newNode;
    115. return;
    116. }
    117. }
    118. }
    119. }
    120. }
    121. /**
    122. * 获取到锁再退出自旋
    123. * 当前线程是head的next节点才能有权限获取锁
    124. * @param node
    125. */
    126. private void acquireQueued(Node node,int arg){
    127. for (;;){
    128. Node pred = node.prev;
    129. // 此条件成立,说明当前node有权限去抢占,去试试
    130. if(pred == head && tryAcquire(arg)){
    131. //抢占成功,将此节点设置为head 并将原head节点出队
    132. setHead(node);
    133. pred.next = null; //help gc
    134. return;
    135. }
    136. //如果当前线程不是head.next,或者并发下抢占失败了 需要挂起
    137. System.out.println("线程:" + Thread.currentThread().getName() + "挂起");
    138. LockSupport.park();
    139. System.out.println("线程:" + Thread.currentThread().getName() + "唤醒");
    140. }
    141. }
    142. @Override
    143. public void unlock() {
    144. release(1);
    145. }
    146. private void release(int arg){
    147. // 释放锁了 可以去看看队列里是否有等待的线程进行唤醒
    148. if(tryRelease(arg)){
    149. Node h = head;
    150. //看看是否有等待线程 h.next == null 则没有
    151. if(h.next != null){
    152. //唤醒h.next
    153. unParkSuccessor(h);
    154. }
    155. }
    156. }
    157. private void unParkSuccessor(Node node){
    158. Node s = node.next;
    159. if(s != null && s.thread != null){
    160. LockSupport.unpark(s.thread);
    161. }
    162. }
    163. // state 减为0 返回true
    164. public boolean tryRelease(int arg){
    165. int c = state - arg;
    166. if(exclusiveOwnerThread != Thread.currentThread()){
    167. throw new Error("无权限");
    168. }
    169. if(c == 0){
    170. exclusiveOwnerThread = null;
    171. state = c;
    172. return true;
    173. }
    174. state = c;
    175. return false;
    176. }
    177. public Node getHead() {
    178. return head;
    179. }
    180. public void setHead(Node node) {
    181. this.head = node;
    182. //当前node已经是获取锁成功的线程了
    183. node.thread = null;
    184. // 当前node成为头结点,则需要将原来前置引用去掉
    185. node.prev = null;
    186. }
    187. public Node getTail() {
    188. return tail;
    189. }
    190. public void setTail(Node tail) {
    191. this.tail = tail;
    192. }
    193. private static final Unsafe unsafe;
    194. private static final long stateOffset;
    195. private static final long headOffset;
    196. private static final long tailOffset;
    197. static {
    198. try{
    199. Field field = Unsafe.class.getDeclaredField("theUnsafe");
    200. field.setAccessible(true);
    201. unsafe = (Unsafe) field.get(null);
    202. stateOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("state"));
    203. headOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("head"));
    204. tailOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("tail"));
    205. } catch (Exception e) {
    206. throw new Error(e);
    207. }
    208. }
    209. private final boolean compareAndSetHead(Node head){
    210. return unsafe.compareAndSwapObject(this,headOffset,null,head);
    211. }
    212. private final boolean compareAndSetTail(Node expect,Node tail){
    213. return unsafe.compareAndSwapObject(this,tailOffset,expect,tail);
    214. }
    215. private final boolean compareAndSetState(int expect,int update){
    216. return unsafe.compareAndSwapObject(this,stateOffset,expect,update);
    217. }
    218. }