1. package com.jx.source.juc.aqs;
    2. import lombok.Data;
    3. import lombok.NoArgsConstructor;
    4. import lombok.extern.slf4j.Slf4j;
    5. import sun.misc.Unsafe;
    6. import java.lang.reflect.Field;
    7. import java.util.concurrent.locks.LockSupport;
    8. /**
    9. * @Description:
    10. * @Author: zhangjx
    11. * @Date: 2021-08-30
    12. **/
    13. @Slf4j
    14. public class MiniReentrantLock implements Lock{
    15. /**
    16. * 0 表示未加锁状态
    17. * >0 表示加锁状态
    18. */
    19. private volatile int state;
    20. /**
    21. * 当前占有锁的线程
    22. * 独占模式 : 统一时间只有一个线程可以持有锁 ,其它的线程未获取到锁时会被阻塞
    23. */
    24. private Thread exclusiveOwnerThread;
    25. /**
    26. * 头节点 head 节点对应的线程是占用锁的线程
    27. */
    28. private Node head;
    29. /**
    30. *尾结点
    31. */
    32. private Node tail;
    33. static Unsafe U;
    34. /**
    35. * state偏移量
    36. */
    37. static long stateOffset;
    38. /**
    39. * head偏移量
    40. */
    41. static long headOffset;
    42. /**
    43. * tail偏移量
    44. */
    45. static long tailOffset;
    46. /**
    47. * 阻塞的线程封装成node节点 放入fifo队列
    48. */
    49. @Data
    50. @NoArgsConstructor
    51. static final class Node{
    52. /**等待线程*/
    53. Thread thread;
    54. /**前置节点*/
    55. Node pre;
    56. /**后置节点*/
    57. Node next;
    58. public Node(Thread thread) {
    59. this.thread = thread;
    60. }
    61. }
    62. static {
    63. try {
    64. final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    65. theUnsafe.setAccessible(true);
    66. U = (Unsafe) theUnsafe.get(null);
    67. stateOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("state"));
    68. headOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("head"));
    69. tailOffset = U.objectFieldOffset(MiniReentrantLock.class.getDeclaredField("tail"));
    70. } catch (Exception e) {
    71. log.error("Unsafe 初始化异常",e);
    72. }
    73. }
    74. protected final boolean compareAndSetHead(Node expectedValue, Node newValue) {
    75. return U.compareAndSwapObject(this, headOffset, expectedValue, newValue);
    76. }
    77. protected final boolean compareAndSetTail(Node expectedValue, Node newValue) {
    78. return U.compareAndSwapObject(this, tailOffset, expectedValue, newValue);
    79. }
    80. protected final boolean compareAndSetState(int expectedValue, int newValue) {
    81. return U.compareAndSwapInt(this, stateOffset, expectedValue, newValue);
    82. }
    83. protected final int getAndIncrementState() {
    84. return U.getAndAddInt(this, state, 1);
    85. }
    86. public void setHead(Node node) {
    87. //当前线程已经是获取锁的线程了
    88. this.head = node;
    89. node.thread = null;
    90. node.pre = null;
    91. }
    92. public int getState() {
    93. return state;
    94. }
    95. public Node getHead() {
    96. return head;
    97. }
    98. public Node getTail() {
    99. return tail;
    100. }
    101. public Thread getExclusiveOwnerThread() {
    102. return exclusiveOwnerThread;
    103. }
    104. /**
    105. * 模拟公平锁
    106. */
    107. @Override
    108. public void lock() {
    109. acquire(1);
    110. }
    111. @Override
    112. public void unLock() {
    113. release(1);
    114. }
    115. private void release(int arg){
    116. if(tryRelease(arg)){
    117. Node h = this.head;
    118. if(h.next != null){
    119. unparkThread(h);
    120. }
    121. }
    122. }
    123. private void unparkThread(Node node){
    124. Node s = node.next;
    125. if(s != null && s.thread != null){
    126. LockSupport.unpark(s.thread);
    127. }
    128. }
    129. /**
    130. * 释放锁成功返回true
    131. * @return
    132. */
    133. private boolean tryRelease(int arg){
    134. int c = getState() - arg;
    135. if(getExclusiveOwnerThread() != Thread.currentThread()){
    136. throw new RuntimeException("must get lock");
    137. }
    138. //执行到这里不存在并发 只有持有锁的线程能够执行到这里
    139. if(c == 0){
    140. /**
    141. * 锁已经完全释放了
    142. * 1、exclusiveOwnerThread设置为空
    143. * 2、state 设置为0
    144. */
    145. this.exclusiveOwnerThread = null;
    146. this.state = 0;
    147. return true;
    148. }else {
    149. this.state = c;
    150. }
    151. return false;
    152. }
    153. /**
    154. * 获取锁成功则返回 否则阻塞
    155. * @param arg
    156. */
    157. private void acquire(int arg){
    158. if(!tryAcquire(arg)){
    159. Node node = addWaiter();
    160. acquireQueued(node,arg);
    161. }
    162. }
    163. /**
    164. *尝试抢锁失败需要做什么?
    165. * 1、将当前线程封装成Node加入队列
    166. * 2、需要将当前线程park掉 使当前线程处于挂起状态
    167. * 唤醒后需要做什么?
    168. * 1、检查当前Node节点是否为head.next节点(head.next节点拥有抢占权限 其他的线程没有抢占权限)
    169. * 2、抢占
    170. * 成功: 将当前node设置为head,将老的head做出队操作
    171. * 失败:继续park 等待被唤醒
    172. */
    173. private void acquireQueued(Node node,int arg){
    174. for (;;){
    175. Node pre = node.pre;
    176. if(pre == head && tryAcquire(arg)){
    177. /**
    178. * 说明当前线程竞争锁成功
    179. * 1、设置当前head为node
    180. * 2、原始head出队
    181. */
    182. setHead(node);
    183. pre.next = node;
    184. return;
    185. }
    186. log.info("当前线程{} 挂起",Thread.currentThread().getName());
    187. //将当前线程挂起
    188. LockSupport.park();
    189. log.info("当前线程{} 唤醒",Thread.currentThread().getName());
    190. }
    191. }
    192. /**
    193. * 尝试获取锁不阻塞线程
    194. * true 抢锁成功
    195. * false 抢锁失败
    196. * @param arg
    197. * 返回false情况:
    198. * 1、cas失败
    199. * 2、state > 0
    200. */
    201. private boolean tryAcquire(int arg){
    202. if(state == 0){
    203. //当state==0时 不能直接抢锁 公平锁 先来后到
    204. if(!hasQueuedThreads() && compareAndSetState(0,arg)){
    205. this.exclusiveOwnerThread = Thread.currentThread();
    206. return true;
    207. }
    208. }else if(Thread.currentThread() == this.exclusiveOwnerThread){
    209. //锁被当前线程占用 重入
    210. int c = getState();
    211. c = c + arg;
    212. this.state = c;
    213. return true;
    214. }
    215. return false;
    216. }
    217. /**
    218. * 判断是否有线程等待
    219. * 什么时候返回false
    220. * 1、 当前队列是空
    221. * 2、 当期线程为head.next节点线程 head.next在任何时候都有权利竞争锁
    222. * @return
    223. */
    224. private boolean hasQueuedThreads(){
    225. Node h = head;
    226. Node t = tail;
    227. Node s;
    228. /**
    229. * 条件1: h != t
    230. * true 说明当前队列已经有node了
    231. * false
    232. * 1、h == t == null 队列中没有node
    233. * 2、h == t == head 第一个获取锁失败的线程会为当前持有锁的线程补充创建一个head节点
    234. * 条件2:s = h.next) != null || s.thread != Thread.currentThread()
    235. * 前置条件: 队列中有node
    236. * 条件2.1 (s = h.next) != null
    237. * 避免 enQueue时的并发情况
    238. * 如当前队列已经有节点a head=a,tail=a, 队列 a ->
    239. * 线程b cas成功 设置a为b的前驱节点 但是还未将a的后继设置为b head = a,tail = b ,队列 a <- b
    240. * 线程c cas成功 设置b为c的前驱节点 head=a,tail=c 队列: a<- b <=> c
    241. *
    242. * 此时head.next虽然为null但是实际上head.next已经被预订了
    243. *
    244. * 条件2.2 s.thread != Thread.currentThread()
    245. * true 当前线程是head.next节点
    246. * false 当前线程不是head.next节点
    247. *
    248. * 如果是 a<=>b b为当前线程节点 返回false 此时当前线程有抢锁资格
    249. * 如果是 a <- b<=>c c为当前线程节点 c没有抢锁资格
    250. */
    251. return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
    252. }
    253. /**
    254. * 当前线程入队
    255. * 返回当前线程对应的Node节点
    256. * 入队流程:
    257. * 队列已经有等待节点
    258. * 1、找到newNode的前置节点 pre
    259. * 2、更新newNode.pre = pre
    260. * 3、CAS更新tail为newNode
    261. * 4、更新pre.next= newNode
    262. *
    263. * @return
    264. */
    265. private Node addWaiter(){
    266. Node newNode = new Node(Thread.currentThread());
    267. //此处不要用tail,用pre保存当前tail,tail可能被修改
    268. Node pre = tail;
    269. if(pre!= null){
    270. newNode.pre = pre;
    271. if(compareAndSetTail(pre,newNode)){
    272. pre.next= newNode;
    273. return newNode;
    274. }
    275. }
    276. /**
    277. * 执行到这里的情况
    278. * 1、tail==null
    279. * 2、CAS设置当前newNode为tail失败
    280. */
    281. enQueue(newNode);
    282. return newNode;
    283. }
    284. /**
    285. * 自旋入队 只有成功后才返回
    286. * 1、tail==null 空队列
    287. * 2、CAS设置当前newNode为tail失败
    288. * @param node
    289. * @return
    290. */
    291. private void enQueue(Node node){
    292. for (;;){
    293. /**
    294. * 1、队列是空
    295. * 说明当前线程是第一个抢锁失败的线程 不然队列应该有一个节点,即当前持有锁线程节点,而当前持有锁的线程由于没有抢锁失败,队列中没有当前持有锁的线程的节点
    296. * 所以当前线程需要为当前持有锁线程建立节点 head节点任何时候都代表占有锁线程节点
    297. */
    298. if(compareAndSetHead(null,node)){
    299. tail = head;
    300. }else {
    301. //说明当前队列已经有node了,需要追加node
    302. Node pre = tail;
    303. if(pre!= null){
    304. node.pre = pre;
    305. if(compareAndSetTail(pre,node)){
    306. pre.next= node;
    307. return;
    308. }
    309. }
    310. }
    311. }
    312. }
    313. }