顾名思义可重入锁

QA一些疑惑

什么是可重入锁

这里的可重入是什么意思?参考了一些文章

  1. 可重入锁指的是在一个线程中可以多次获取同一把锁,比如:一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法,而无需重新获得锁;

  2. synchronized锁也是个可重入锁,比如一个类当中的两个非静态方法都被synchronized修饰,则线程在获取synchronized锁访问一个方法时是可以进入另一个synchronized方法的(PS:应该也能进入static方法的synchronized修饰临界区的,因为是两把不同的锁,表现的不是可重入的特性)

    和不可重入锁的对比

    二者的主要区别在于,不可重入锁只允许被获取一次,即使是已经持有该锁的线程也无法再次获取。相反,可重入锁允许同一个线程重复地获取该锁。
    从概念上可以发现不可重入锁的一个缺陷:即使是已经持有该锁的线程也无法再次获取该锁,那么容易联想到以下情况,让methodA调用了methodB:
    线程在进入methodA的同步代码块时,成功获取到了锁,并调用了methodB。但是在进入methodB的同步代码块时,由于锁计数为1,只能等待锁释放。这就造成了死锁。 ```java public class Test { public void methodA(){

    1. synchronized (this){
    2. System.out.println("This is methodA");
    3. methodB();
    4. }

    }

    public void methodB(){

    1. synchronized (this){
    2. System.out.println("This is methodB");
    3. }

    } } //先释放再调用 public void methodA(){ synchronized (this){

    1. System.out.println("This is methodA");

    } methodB(); }

public void methodB(){ synchronized (this){ System.out.println(“This is methodB”); } }

  1. 如果先释放锁再调用methodB,拆分代码来写可以解决,但是这样在编写时就需要从后向前考虑和设计,而不是从前向后。换句话说,你能预测将来要写methodCmethodD的时候为了避免死锁从而拆分前面的代码吗。这时可重入锁出现了,同一线程可以多次获取这个锁。
  2. <a name="K48AY"></a>
  3. ## 关于自旋锁
  4. [https://www.cnblogs.com/cxuanBlog/p/11679883.html](https://www.cnblogs.com/cxuanBlog/p/11679883.html)
  5. <a name="TJekg"></a>
  6. ## 实现原理
  7. 1. 获取的时候如果state==0,那么正常获取,同时记录拥有同步状态的是当前线程,cas更新状态为1;如果state!=0,就要看拥有同步状态的线程是不是和当前线程一样,一样的话,获取成功,同时casstate+1,不一样则进入同步队列里边自旋阻塞
  8. 1. 释放:释放的时候state-1, 如果减到了0,表示释放成功了,否则没有释放成功
  9. <a name="Xnv9m"></a>
  10. ## 公平与非公平
  11. 公平就是先尝试获取锁的线程会先得到多,非公平则是去竞争锁,默认是非公平的锁<br />公平的锁多一次判断,导致性能损失,可以避免饥饿<br />非公平的性能会更高,但是可能会产生饥饿<br />实现方面非公平和公平的区别就tryAcquire方法不一样<br />公平的相比于非公平的会多判断一个 !hasQueuedPredecessors(),hasQueuedPredecessors是判断当前节点是否有前驱节点,如果有,证明有比当前节点等待时间长的节点,所以此时失败,返回false,继续等
  12. ```java
  13. // 同步队列为空,或者当前节点是头节点 返回false, 返回false,tryAcquire才可能返回true,保证了先来后到
  14. public final boolean hasQueuedPredecessors() {
  15. Node t = tail; // Read fields in reverse initialization order
  16. Node h = head;
  17. Node s;
  18. return h != t &&
  19. ((s = h.next) == null || s.thread != Thread.currentThread());
  20. }

源码

  1. public class ReentrantLock implements Lock, java.io.Serializable {
  2. private static final long serialVersionUID = 7373984872572414699L;
  3. private final Sync sync;
  4. // 跟我们使用AQS一样,也是继承他然后定义一些自己的规则
  5. abstract static class Sync extends AbstractQueuedSynchronizer {
  6. private static final long serialVersionUID = -5179523762034025860L;
  7. abstract void lock();
  8. final boolean nonfairTryAcquire(int acquires) {
  9. final Thread current = Thread.currentThread();
  10. int c = getState();
  11. // 状态是0表示没有被获取,进行CAS并在CAS成功时返回true
  12. if (c == 0) {
  13. if (compareAndSetState(0, acquires)) {
  14. // 这个是公平性的保证,他记录了谁获取到同步状态
  15. setExclusiveOwnerThread(current);
  16. return true;
  17. }
  18. }
  19. else if (current == getExclusiveOwnerThread()) {
  20. // 有线程获取了锁,这个线程是自己
  21. int nextc = c + acquires;
  22. // 很严谨
  23. if (nextc < 0) // overflow
  24. throw new Error("Maximum lock count exceeded");
  25. // 可以思考下这里为什么不需要CAS,而前面需要
  26. setState(nextc);
  27. return true;
  28. }
  29. return false;
  30. }
  31. protected final boolean tryRelease(int releases) {
  32. int c = getState() - releases;
  33. // 不能释放别人的锁,释放别人的锁感觉是不会出现的,这里很严谨
  34. if (Thread.currentThread() != getExclusiveOwnerThread())
  35. throw new IllegalMonitorStateException();
  36. boolean free = false;
  37. if (c == 0) {
  38. free = true;
  39. // 减到0,就说没有线程在占据锁了
  40. setExclusiveOwnerThread(null);
  41. }
  42. // 更新下状态,这里也是不用CAS,很有学问
  43. setState(c);
  44. // 一直要减到0才说你是释放成功的,这是很自然的事情
  45. return free;
  46. }
  47. protected final boolean isHeldExclusively() {
  48. // 这里直接判断占据锁的线程是不是和当前线程是一个,是的话,就是拿到锁了
  49. // 这说明我们之前写的锁的实现,这个位置是有点问题的
  50. return getExclusiveOwnerThread() == Thread.currentThread();
  51. }
  52. // Condition后边再说
  53. final ConditionObject newCondition() {
  54. return new ConditionObject();
  55. }
  56. final Thread getOwner() {
  57. return getState() == 0 ? null : getExclusiveOwnerThread();
  58. }
  59. final int getHoldCount() {
  60. return isHeldExclusively() ? getState() : 0;
  61. }
  62. // =0就是锁了
  63. final boolean isLocked() {
  64. return getState() != 0;
  65. }
  66. // 这个是与序列化相关的东西
  67. private void readObject(java.io.ObjectInputStream s)
  68. throws java.io.IOException, ClassNotFoundException {
  69. s.defaultReadObject();
  70. setState(0); // reset to unlocked state
  71. }
  72. }
  73. static final class NonfairSync extends Sync {
  74. private static final long serialVersionUID = 7316153563782823691L;
  75. final void lock() {
  76. // TODO: 这里有别于FairSync,但是我没看得懂为什么FairSync不这么写
  77. // 或者这里为什么要这么写
  78. if (compareAndSetState(0, 1))
  79. setExclusiveOwnerThread(Thread.currentThread());
  80. else
  81. acquire(1);
  82. }
  83. // 直接调用了Sync里边的nonfairTryAcquire, 这很自然
  84. protected final boolean tryAcquire(int acquires) {
  85. return nonfairTryAcquire(acquires);
  86. }
  87. }
  88. static final class FairSync extends Sync {
  89. private static final long serialVersionUID = -3000897897090466540L;
  90. // 公平的lock是直接调了acquire,
  91. final void lock() {
  92. acquire(1);
  93. }
  94. protected final boolean tryAcquire(int acquires) {
  95. final Thread current = Thread.currentThread();
  96. int c = getState();
  97. if (c == 0) {
  98. // 他会查询有没有比你当前线程等的时间更长的线程,这个就是保证公平性了
  99. if (!hasQueuedPredecessors() &&
  100. compareAndSetState(0, acquires)) {
  101. setExclusiveOwnerThread(current);
  102. return true;
  103. }
  104. }
  105. else if (current == getExclusiveOwnerThread()) {
  106. int nextc = c + acquires;
  107. if (nextc < 0)
  108. throw new Error("Maximum lock count exceeded");
  109. setState(nextc);
  110. return true;
  111. }
  112. return false;
  113. }
  114. }
  115. public ReentrantLock() {
  116. // 默认是非公平
  117. sync = new NonfairSync();
  118. }
  119. // 可以指定要公平的还是非公平的锁
  120. public ReentrantLock(boolean fair) {
  121. sync = fair ? new FairSync() : new NonfairSync();
  122. }
  123. public void lock() {
  124. sync.lock();
  125. }
  126. public void lockInterruptibly() throws InterruptedException {
  127. sync.acquireInterruptibly(1);
  128. }
  129. public boolean tryLock() {
  130. return sync.nonfairTryAcquire(1);
  131. }
  132. public boolean tryLock(long timeout, TimeUnit unit)
  133. throws InterruptedException {
  134. return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  135. }
  136. public void unlock() {
  137. sync.release(1);
  138. }
  139. public Condition newCondition() {
  140. return sync.newCondition();
  141. }
  142. public int getHoldCount() {
  143. return sync.getHoldCount();
  144. }
  145. public boolean isHeldByCurrentThread() {
  146. return sync.isHeldExclusively();
  147. }
  148. public boolean isLocked() {
  149. return sync.isLocked();
  150. }
  151. public final boolean isFair() {
  152. return sync instanceof FairSync;
  153. }
  154. protected Thread getOwner() {
  155. return sync.getOwner();
  156. }
  157. public final boolean hasQueuedThreads() {
  158. return sync.hasQueuedThreads();
  159. }
  160. public final boolean hasQueuedThread(Thread thread) {
  161. return sync.isQueued(thread);
  162. }
  163. public final int getQueueLength() {
  164. return sync.getQueueLength();
  165. }
  166. protected Collection<Thread> getQueuedThreads() {
  167. return sync.getQueuedThreads();
  168. }
  169. public boolean hasWaiters(Condition condition) {
  170. if (condition == null)
  171. throw new NullPointerException();
  172. if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
  173. throw new IllegalArgumentException("not owner");
  174. return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
  175. }
  176. public int getWaitQueueLength(Condition condition) {
  177. if (condition == null)
  178. throw new NullPointerException();
  179. if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
  180. throw new IllegalArgumentException("not owner");
  181. return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
  182. }
  183. protected Collection<Thread> getWaitingThreads(Condition condition) {
  184. if (condition == null)
  185. throw new NullPointerException();
  186. if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
  187. throw new IllegalArgumentException("not owner");
  188. return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
  189. }
  190. public String toString() {
  191. Thread o = sync.getOwner();
  192. return super.toString() + ((o == null) ?
  193. "[Unlocked]" :
  194. "[Locked by thread " + o.getName() + "]");
  195. }
  196. }