轻量级锁和重量级锁
读多写少 => 用轻量级锁Reentranlock,原子类。其原理是CAS比较并交换
自旋递增(unsafe类do while)逻辑。
写多读少 => 用重量级锁synchronized,Lock。而synchronized的实现原
理是依赖操作系统的互斥锁实现线程的同步。
CAS比较并交换算法的弊端
1、aba问题用版本号递增解决
2、自旋等待耗cpu资源,自旋时间超过cpu状态切换时间不建议用轻量级锁。
3、多个共享变量操作用AtomicReference类。
自旋锁
原子类也是自旋锁,应用场景是自旋时间小于cpu状态切换的时间。
偏向锁
同步代码块只有一个线程访问,则不会有加锁解锁操作,原理是Mark Word
会记录线程id。如果有其他线程访问,会升级成轻量级锁,如果自旋超过
一定次数,并且有第三个线程访问,会升级为重量级锁。锁降级是指当前
把持住写锁,再获取到读锁,随后释放(先前拥有的)写锁的过程。
公平锁和非公平锁
公平锁是线程访问同步代码块时按顺序排队获取锁,优点是队列中的线程
不会饿死,缺点性能比非公平锁低,因为需要按顺序唤醒阻塞线程,cpu状
态需要切换。
非公平锁是可能后申请获取锁的线程先获得锁,即在锁刚好可用的时候。
优点减少cpu状态切换,提高性能,缺点是队列中的线程可能会饿死。
ReentranLock可实现公平锁和非公平锁。
公平锁和非公平锁原理是分别是增加队列和判断status是否为0
可重入锁和非可重入锁
可重入锁是线程进入两个方法同步代码块里的锁如果是同一个则都能
获得锁,ReentrantLock和synchronized都是可重入锁,可重入锁优点
是可一定程度避免死锁。非可重入锁和可重入锁相反。
实现方式:可重入锁会判断下当前线程是否是获取过锁的线程,然后
status加一;释放则减一,如果状态为0则表示释放了锁。非可重入
锁判断status的状态(compareAndSwapStatus)来是否可以获得锁,
如果可以则status加一。
独享锁(排它锁)和共享锁
ReentrantReadWriteLock有两把锁:ReadLock和WriteLock,读锁是
共享锁,写锁是独享锁。写写、写读互斥。公平锁和非公平锁都是
获取的互斥锁(ReentranLock),所以是独享锁。
总结
读多写少 => 用轻量级锁Reentranlock,原子类
读少写多 => 用重量级锁synchronized,Lock
自旋时间小于cpu状态切换的时间用自旋锁(CAS即比较并交换算法)
按先后顺序获取锁防止先到线程饿死忽略性能用公平锁。谁抢到就是谁的,
为了提高性能,忽略线程饿死则用非公平锁。公平锁和非公平锁都可用
ReentranLock实现。ReentrantLock和synchronized都是可重入锁。
ReadLock和WriteLock,读锁是共享锁,写锁是独享锁。ReentranLock是独享锁。
Reentranlock、原子类可以是轻量级锁、可重入锁、公平锁或非公平锁、自旋锁、独享锁
synchronized、Lock是重量级锁、可重入锁
ReadLock是共享锁,WriteLock是独享锁
强烈推荐在多线程应用程序中使用synchronized,因为实现方便,后续工作由JVM来完成,
可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。
在高并发量的条件下,synchronized性能会迅速下降几十倍,而ReentrantLock的性能却能依然维持一个水准。
ReentrantLock默认为非公平锁。这是因为,非公平锁实际执行的效率要远远超出公平锁。
使用ReentrantLock必须在finally控制块中进行解锁操作。
读写锁比较适用于读多写少的应用场景