synchronized

原理

https://www.cnblogs.com/wuzhenzhao/p/10250801.html

应用方式

  1. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
  2. 静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
  3. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

    ReentrantLock

    特性

  4. 可重入锁

  5. 可响应中断
  6. 可尝试加锁
  7. 限时等待尝试加锁
  8. 公平锁、非公平锁
  9. 与Condition信号量结合使用

    原理

    使用AQS实现
    入锁简单理解就是对同一个线程而言,它可以重复的获取锁

    应用

  10. lock() 获得锁就返回true,不能的话一直等待获得锁

  11. tryLock() 尝试获取锁成功就返回true,不能就直接返回false,不会等待
  12. tryLock(long timeout,TimeUnit unit) 跟tryLock一样,尝试获取锁,如果超过该时间段还没获得锁,返回false
  13. lockInterruptibly 获取锁,跟lock不一样的地方是,过程中会检测是否中断(interrupt),若是会抛出异常
  14. 构造函数 public ReentrantLock(boolean fair) 可设置公平锁还是非公平锁

    Condition

    1. public interface Condition {
    2. //使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
    3. void await() throws InterruptedException;
    4. //调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    5. //调用该方法后,结束等待的唯一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程中如果当前线程被中断,该方法仍然会继续等待,同时保留该线程的中断状态。
    6. void awaitUninterruptibly();
    7. // 调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    8. //nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;
    9. //若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。
    10. long awaitNanos(long nanosTimeout) throws InterruptedException;
    11. //与await()基本一致,唯一不同点在于,指定时间之内没有收到signal()或signalALL()信号或者线程中断时该方法会返回false;其它情况返回true。
    12. boolean await(long time, TimeUnit unit) throws InterruptedException;
    13. //适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的某一时刻。
    14. boolean awaitUntil(Date deadline) throws InterruptedException;
    15. //唤醒一个在 await()等待队列中的线程。与Object.notify()相似
    16. void signal();
    17. //唤醒 await()等待队列中所有的线程。与object.notifyAll()相似
    18. void signalAll();
    19. }

    AQS

    AbstractQueuedSynchronizer是一个基于队列的锁

    子类

  15. Node 等待锁队列的节点

  16. ConditionObject 等待条件满足的队列节点

    主要构成

  17. private transient volatile Node head 头节点

  18. private transient volatile Node tail 尾节点
  19. private volatile int state; 同步状态(可以理解成是否加锁) 0-未加锁 n-加锁后重入的次数

    lock加锁

  20. tryAcquire尝试获取锁: 公平锁(如果是第一个元素获取锁,否则加入等待队列),非公平锁(直接争抢锁,失败则进入等待队列)

  21. addWaiter 将当前线程加入等待队列
  22. acquireQueued 自旋获取锁,如果前面的节点是头节点,那么tryAcquire,获取成功则自己成为头节点,否则进入4
  23. shouldParkAfterFailedAcquire 是否应该挂起自己,如果前面节点的等待状态是SIGNAL(-1)就挂起,(如果前面等待状态>0,就递归找到不大于0的节点,然后将他的next设置为自己,如果等待状态是0,将前一个节点的等待状态设置为SIGNAL(-1))否则不挂起
  24. 如果挂起,读取当前线程的中断状态Thread.interrupted(),如果被中断就自己响应中断Thread.currentThread().interrupt()

    relaese释放锁

  25. 减少重入次数,如果为0,设置state=0,相当于释放锁

  26. 如果头节点的等待状态<0,则设置为0.然后获取next节点,如果为空或者取消的话,从队尾遍历找到<0的节点,然后唤醒

    CountDownLatch

    Semaphore