- synchronized 关键字隐式地获取锁,将锁的获取和释放固化,简化了同步的管理,但扩展性没有显式的锁获取和释放强。
- Lock 接口提供的 synchronized 不具备的特性:
- 尝试非阻塞地获取锁。
- 能被中断地获取锁,当获取到锁的线程被中断时,中断异常将被抛出,同时锁被释放。
- 超时获取锁,截止时间到了仍旧无法获得锁,则返回。
- AbstractQueuedSynchronizer 队列同步器:模板方法模式,简化了锁的实现方式,屏蔽了同步状态管理、线程排队和等待 唤醒等底层操作,自身没有实现任何同步接口,可重写模板方法分为三类:
- 独占式获取与释放同步状态。
- 共享式获取与释放同步状态。
- 查询同步队列中的等待线程情况。
- AQS 的实现:FIFO 双向队列,首节点是获取同步状态成功的节点。
- 只有一个线程能够成功获取到同步状态,因此设置头节点不需要 CAS 保证。
- 无法获取到同步状态的线程被构造为节点加入同步队列,因而设置尾节点需要基于 CAS 保证线程安全。
- 可重入锁:锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,释放时计数自减,当计数为 0 时,表示锁已经成功释放。
- 公平锁与非公平锁实现区别:公平锁在判断条件增加了一个
hasQueuedPredecessors()
方法,判断同步队列中当前节点是否有前驱节点,即更早请求获取锁的线程。
- 公平锁效率通常不如非公平锁高,但能够减少“饥饿”发生的概率,等待越久的线程能够优先被满足。
- 非公平锁中同一线程连续获取锁的概率非常高,刚刚释放锁后获取同步状态相对更加容易。
- 非公平锁线程切换次数更少,虽然容易造成饥饿,但保证了更大吞吐量。
- ReentrantReadWriteLock:读写锁,整型变量中高 16 位维护读状态,低 16 位维持写状态。
- 存在读锁,则写锁不能被获取,需要等待,以保证写锁的操作对读锁可见。
- 锁降级:获取写锁,再获取读锁,随后释放写锁。
- 不支持锁升级:保证数据可见性,若读锁被多个线程获取,升级后更新对其他获取到读锁的线程均不可见。
- condition:提供监视器方法,AQS 的内部类。
- 同步队列的首节点并不会直接加入等待队列,而是通过
addConditionWaiter()
方法把当前线程构造成一个新的节点并将其加入等待队列中。