显示锁
显示锁可以代替 synchronized 吗?
只有当 synchronized 不适用时,如中断,非块结构加锁,是可以代替的一种高级锁。
Lock 和 ReentrantLock
Lock 定义了显示锁的方法属性:
1 | public interfece Lock |
ReentrantLock是可重入的实现
Lock 和 synchronized 的区别?
Lock接口中定义了一种无条件、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的。
Lock接口提供了与synchronized相同的互斥性和内存可见性,而在加锁语义,调度算法,顺序保障和性能特性方面有所不同。
lock在哪些场景下使用?
- 轮询锁,可以解决死锁,tryLock()获取失败则返回,
- 定时锁和可中断的锁获取操作,tryLock(timeOut)等待超时返回,可中断
- 非块结构加锁(连锁式加锁或者锁耦合)
- 要求公平性的业务场景
Lock 性能比 synchronized 好?
在Java5.0中,ReentrantLock能提供更高的吞吐量,但在Java6中,二者的吞吐量非常接近
总的来说,两者基本性能都很奈斯
没有永远的好与坏
公平性
什么是公平锁和非公平锁?分别对应什么应有场景?
公平锁,必须要求排队,先进先出,会带来额外的阻塞和唤醒等额外的开销
公平锁,必须要求排队,先进先出,会带来额外的阻塞和唤醒等额外的开销
非公平锁,获取锁失败才加入排队,但会带来“饥饿”的可能
当持有锁的时间相对较长,或者请求锁的平局时间间隔较长,非公平锁带来的性能提升不会明显,如果公平锁更符合业务场景,那么应该使用公平锁
内置锁默认为非公平锁
在 synchronized 和 ReentrantLock 间选择?
当 synchronized 不适用才使用 ReentrantLock
读写锁
1 | public interface ReadWriteLock { |
一个资源能同时被多个读操作访问,或者只能被一个写操作访问,但两者不能同时进行。
这句话很关键
读写锁交互实现策略:
- 释放优先级:写锁释放时,其他线程是读优先,还是写优先,还是先来的优先
- 读线程插队:锁被读线程持有,且有写线程在等待,后续读线程能否插队?能插队的性能更高,但是数据上可能会有问题。
- 重入性:是否可重入,主要是写线程的重入
- 降级:写锁保存的范围降低为读锁来保存,目的是为了增加并发性
- 升级:不应该支持,会导致死锁(两个线程在获取读锁后,同时升级的话会死锁)
降级的案例:
1 | class CachedData { |
ReentrantWriteReadLock 的实现策略?
默认为非公平锁,释放优先级不确定,不允许读线程查询,可重入,支持降级,不支持升级
ReentrantWriteReadLock 和 ReentrantLock 的性能对比?
对于在多处理器系统上被频繁读取的数据结构,读 - 写锁能够提高性能。而在其他情况下,读 - 写锁的性能比独占锁的性能要略差一些,这是因为它们的复杂性更高