参考:https://www.jianshu.com/p/4358b1466ec9

前言:

先来想象一个场景:手把手的进行锁获取和释放,先获得锁A,然后再获取锁B,当获取锁B后释放锁A同时获取锁C,当锁C获取后,再释放锁B同时获取锁D,以此类推,这种场景下,synchronized关键字就不那么容易实现了,而使用Lock却显得容易许多。

源码:

  1. public class ReentrantLock implements Lock, java.io.Serializable {
  2. private final Sync sync;
  3. abstract static class Sync extends AbstractQueuedSynchronizer {
  4.  
  5. /**
  6. * Performs {@link Lock#lock}. The main reason for subclassing
  7. * is to allow fast path for nonfair version.
  8. */
  9. abstract void lock();
  10.  
  11. /**
  12. * Performs non-fair tryLock. tryAcquire is implemented in
  13. * subclasses, but both need nonfair try for trylock method.
  14. */
  15. final boolean nonfairTryAcquire(int acquires) {
  16. final Thread current = Thread.currentThread();
  17. int c = getState();
  18. if (c == 0) {
  19. if (compareAndSetState(0, acquires)) {
  20. setExclusiveOwnerThread(current);
  21. return true;
  22. }
  23. }
  24. else if (current == getExclusiveOwnerThread()) {
  25. int nextc = c + acquires;
  26. if (nextc < 0) // overflow
  27. throw new Error("Maximum lock count exceeded");
  28. setState(nextc);
  29. return true;
  30. }
  31. return false;
  32. }
  33.  
  34. protected final boolean tryRelease(int releases) {
  35. int c = getState() - releases;
  36. if (Thread.currentThread() != getExclusiveOwnerThread())
  37. throw new IllegalMonitorStateException();
  38. boolean free = false;
  39. if (c == 0) {
  40. free = true;
  41. setExclusiveOwnerThread(null);
  42. }
  43. setState(c);
  44. return free;
  45. }
  46.  
  47. }
  48. //默认非公平锁
  49. public ReentrantLock() {
  50. sync = new NonfairSync();
  51. }
  52. //fair为false时,采用公平锁策略
  53. public ReentrantLock(boolean fair) {
  54. sync = fair ? new FairSync() : new NonfairSync();
  55. }
  56. public void lock() {
  57. sync.lock();
  58. }
  59. public void unlock() { sync.release(1);}
  60. public Condition newCondition() {
  61. return sync.newCondition();
  62. }
  63. ...
  64. }

使用方式:

  1. Lock lock = new ReentrantLock();
  2. Condition condition = lock.newCondition();
  3. lock.lock();
  4. try {
  5. while(条件判断表达式) {
  6. condition.wait();
  7. }
  8. // 处理逻辑
  9. } finally {
  10. lock.unlock();//保证锁在最后能够释放 注意!!!!一定要释放
  11. }

非公平锁:

当线程获取锁失败的时候,同样可以自旋获取锁,超过自旋次数才会进入队列尾部

  • 线程A和B同时执行CAS指令,假设线程A成功,线程B失败,则表明线程A成功获取锁,并把同步器中的exclusiveOwnerThread设置为线程A。
  • 竞争失败的线程B,在nonfairTryAcquire方法中,会再次尝试获取锁,Doug lea会在多处尝试重新获取锁,应该是在这段时间如果线程A释放锁,线程B就可以直接获取锁而不用挂起
  1. static final class NonfairSync extends Sync {
  2. /**
  3. * Performs lock. Try immediate barge, backing up to normal
  4. * acquire on failure.
  5. */
  6. final void lock() {
  7. if (compareAndSetState(0, 1))
  8. setExclusiveOwnerThread(Thread.currentThread());
  9. else
  10. acquire(1);
  11. }
  12.  
  13. public final void acquire(int arg) {
  14. if (!tryAcquire(arg) &&
  15. acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
  16. selfInterrupt();
  17. }
  18.  
  19. protected final boolean tryAcquire(int acquires) {
  20. return nonfairTryAcquire(acquires);
  21. }
  22. }

公平锁:

在公平锁中,每当线程执行lock方法时,如果同步器的队列中有线程在等待,则直接加入到队列尾部。

  1. static final class FairSync extends Sync {
  2. private static final long serialVersionUID = -3000897897090466540L;
  3.  
  4. final void lock() {
  5. acquire(1);
  6. }
  7.  
  8. /**
  9. * Fair version of tryAcquire. Don't grant access unless
  10. * recursive call or no waiters or is first.
  11. */
  12. protected final boolean tryAcquire(int acquires) {
  13. final Thread current = Thread.currentThread();
  14. int c = getState();
  15. if (c == 0) {
  16. if (!hasQueuedPredecessors() &&
  17. compareAndSetState(0, acquires)) {
  18. setExclusiveOwnerThread(current);
  19. return true;
  20. }
  21. }
  22. else if (current == getExclusiveOwnerThread()) {
  23. int nextc = c + acquires;
  24. if (nextc < 0)
  25. throw new Error("Maximum lock count exceeded");
  26. setState(nextc);
  27. return true;
  28. }
  29. return false;
  30. }
  31. }

重入锁:

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

  1. if (current == getExclusiveOwnerThread()) {
  2. int nextc = c + acquires;
  3. if (nextc < 0)
  4. throw new Error("Maximum lock count exceeded");
  5. setState(nextc);
  6. return true;
  7. }

条件变量:

  1. public class ConditionObject implements Condition, java.io.Serializable {
  2. /** First node of condition queue. */
  3. private transient Node firstWaiter;
  4. /** Last node of condition queue. */
  5. private transient Node lastWaiter;
  6. public final void signal() {}
  7. public final void signalAll() {}
  8. public final void awaitUninterruptibly() {}
  9. public final void await() throws InterruptedException {}
  10. }
  • Synchronized中,所有的线程都在同一个object的条件队列上等待。而ReentrantLock中,每个condition都维护了一个条件队列。
  • 每一个Lock可以有任意数据的Condition对象,Condition是与Lock绑定的,所以就有Lock的公平性特性:如果是公平锁,线程为按照FIFO的顺序从Condition.await中释放,如果是非公平锁,那么后续的锁竞争就不保证FIFO顺序了。
  • Condition接口定义的方法,await对应于Object.waitsignal对应于Object.notifysignalAll对应于Object.notifyAll。特别说明的是Condition的接口改变名称就是为了避免与Object中的wait/notify/notifyAll的语义和使用上混淆。

 await实现逻辑:

  1. 将线程A加入到条件等待队列中,如果最后一个节点是取消状态,则从对列中删除。
  2. 线程A释放锁,实质上是线程A修改AQS的状态state为0,并唤醒AQS等待队列中的线程B,线程B被唤醒后,尝试获取锁,接下去的过程就不重复说明了。
  3. 线程A释放锁并唤醒线程B之后,如果线程A不在AQS的同步队列中,线程A将通过LockSupport.park进行挂起操作。
  4. 随后,线程A等待被唤醒,当线程A被唤醒时,会通过acquireQueued方法竞争锁,如果失败,继续挂起。如果成功,线程A从await位置恢复。

signal实现逻辑:

  1. 接着上述场景,线程B执行了signal方法,取出条件队列中的第一个非CANCELLED节点线程,即线程A。另外,signalAll就是唤醒条件队列中所有非CANCELLED节点线程。遇到CANCELLED线程就需要将其从队列中删除。
  2. 通过CAS修改线程A的waitStatus为0,表示该节点已经不是等待条件状态,并将线程A插入到AQS的等待队列中。
  3. 唤醒线程A,线程A和别的线程进行锁的竞争。

ReentrantLock学习笔记的更多相关文章

  1. ReentrantLock 学习笔记

    有篇写的很不错的博客:https://blog.csdn.net/aesop_wubo/article/details/7555956    基于JDK1.8 参考着看源码 ,弄清楚lock()和un ...

  2. ReentrantLock 相关学习笔记

    ReentrantLock 相关学习笔记 标签(空格分隔): Java多线程 Java接口Lock有三个实现类:ReentrantLock.ReentrantReadWriteLock.ReadLoc ...

  3. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  4. JUC.Condition学习笔记[附详细源码解析]

    目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...

  5. JUC.Lock(锁机制)学习笔记[附详细源码解析]

    锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...

  6. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  7. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

  8. 学习笔记 07 --- JUC集合

    学习笔记 07 --- JUC集合 在讲JUC集合之前我们先总结一下Java的集合框架,主要包含Collection集合和Map类.Collection集合又能够划分为LIst和Set. 1. Lis ...

  9. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

随机推荐

  1. World Wind Java开发之一(转)

    http://blog.csdn.net/giser_whu/article/details/40477235 参照<World wind Java三维地理信息系统开发指南随书光盘>以及官 ...

  2. 1.redis 安装

    1.https://redis.io/download. 2. $ wget http://download.redis.io/releases/redis-3.2.9.tar.gz $ .tar.g ...

  3. 四面体ply格式文件图和数据对应关系分析

    通过一个简单的文件来理解ply格式的文件是有所帮助的,我在网上找了一个四面体的ply文件,我通过meshlab打开看到的效果如下所示,我录制成gif文件,希望可以从不同角度展示出来: 同时我截图少许, ...

  4. CUDA中记录执行时间-GPU端

    事件eventcudaEvent_t start,stop;cudaEventCreate(&start);cudaEventCreate(&stop);cudaEventRecord ...

  5. oracle用户创建及权限设置(转)

    权限: create session create table unlimited tablespace connect resource dba 例: #sqlplus /nolog SQL> ...

  6. Java代码工具箱_用Set给List/Vector去重

    参考 方法一:需要2个容器,1个迭代去重,1个作为结果容器. 此方法其实想法比较简单也是正常思路: package com.yonyou.test; import java.util.List; im ...

  7. LigerUi中表(Grid)控件的相关属性笔记

    http://blog.csdn.net/dxnn520/article/details/8216560 // ========================================= [每 ...

  8. 转+更新 Graphviz 教程,例子+ 高级应用 写代码,编程绘制架构图(分层拓扑图) 转自官网

    1. Graphviz介绍 Graphviz是大名鼎鼎的贝尔实验室的几位牛人开发的一个画图工具. 它的理念和一般的“所见即所得”的画图工具不一样,是“所想即所得”. Graphviz提供了dot语言来 ...

  9. MySQL 5.6常用参数配置及说明

    [client] user = root password = Yong_110 [mysql] prompt = [\\u@\\p][\\d]>\\_ no-auto-rehash [mysq ...

  10. advanced regression to predict housing prices

    https://docs.google.com/presentation/d/e/2PACX-1vQGlXP6QZH0ATzXYwnrXinJcCn00fxCOoEczPAXU-n3hAPLUfMfi ...