synchronized
原理
https://www.cnblogs.com/wuzhenzhao/p/10250801.html
应用方式
- 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
- 静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
ReentrantLock
特性
可重入锁
- 可响应中断
- 可尝试加锁
- 限时等待尝试加锁
- 公平锁、非公平锁
-
原理
使用AQS实现
入锁简单理解就是对同一个线程而言,它可以重复的获取锁应用
lock() 获得锁就返回true,不能的话一直等待获得锁
- tryLock() 尝试获取锁成功就返回true,不能就直接返回false,不会等待
- tryLock(long timeout,TimeUnit unit) 跟tryLock一样,尝试获取锁,如果超过该时间段还没获得锁,返回false
- lockInterruptibly 获取锁,跟lock不一样的地方是,过程中会检测是否中断(interrupt),若是会抛出异常
构造函数 public ReentrantLock(boolean fair) 可设置公平锁还是非公平锁
Condition
public interface Condition {
//使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
void await() throws InterruptedException;
//调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
//调用该方法后,结束等待的唯一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程中如果当前线程被中断,该方法仍然会继续等待,同时保留该线程的中断状态。
void awaitUninterruptibly();
// 调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
//nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;
//若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。
long awaitNanos(long nanosTimeout) throws InterruptedException;
//与await()基本一致,唯一不同点在于,指定时间之内没有收到signal()或signalALL()信号或者线程中断时该方法会返回false;其它情况返回true。
boolean await(long time, TimeUnit unit) throws InterruptedException;
//适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的某一时刻。
boolean awaitUntil(Date deadline) throws InterruptedException;
//唤醒一个在 await()等待队列中的线程。与Object.notify()相似
void signal();
//唤醒 await()等待队列中所有的线程。与object.notifyAll()相似
void signalAll();
}
AQS
AbstractQueuedSynchronizer是一个基于队列的锁
子类
Node 等待锁队列的节点
-
主要构成
private transient volatile Node head
头节点private transient volatile Node tail
尾节点private volatile int state;
同步状态(可以理解成是否加锁) 0-未加锁 n-加锁后重入的次数lock加锁
tryAcquire尝试获取锁: 公平锁(如果是第一个元素获取锁,否则加入等待队列),非公平锁(直接争抢锁,失败则进入等待队列)
- addWaiter 将当前线程加入等待队列
- acquireQueued 自旋获取锁,如果前面的节点是头节点,那么tryAcquire,获取成功则自己成为头节点,否则进入4
- shouldParkAfterFailedAcquire 是否应该挂起自己,如果前面节点的等待状态是SIGNAL(-1)就挂起,(如果前面等待状态>0,就递归找到不大于0的节点,然后将他的next设置为自己,如果等待状态是0,将前一个节点的等待状态设置为SIGNAL(-1))否则不挂起
如果挂起,读取当前线程的中断状态Thread.interrupted(),如果被中断就自己响应中断Thread.currentThread().interrupt()
relaese释放锁
减少重入次数,如果为0,设置state=0,相当于释放锁
- 如果头节点的等待状态<0,则设置为0.然后获取next节点,如果为空或者取消的话,从队尾遍历找到<0的节点,然后唤醒
CountDownLatch
Semaphore