1.公平锁和非公平锁
公平锁:多个线程按照申请锁的顺序来获取锁;(类似排队打饭,先来后到)
非公平锁:多个线程并非按照申请锁的顺序,有可能后申请的线程先得到锁。(在高并发场景下,有可能会造成优先级反转或饥饿现象)
实现原理:多线程场景下,如果去检查锁维护的等待队列,如果队列为空或当前线程是队列中的队首元素则获取锁,否则就会加入等待队列,按照FIFO的规则等到排队到自己再获取锁。非公平锁上来就尝试去抢占锁,没有成功再排队。
ReentrantLock 默认是非公平锁,比公平锁性能好,吞吐量更大。
Synchronized 也是非公平锁.
2.可重入锁和递归锁
可重入锁就是递归锁,就相当于一个别名.
可重入锁:同一线程外层方法获取锁后,内层递归调用的方法仍自动获取这把锁。
即,线程可以进入任何一个它已经拥有的锁所同步着的代码块。
ReentrantLock/Synchronized 就是一个经典的可重入锁
作用:防止死锁。
锁的基本原理是,基于将多线程并行任务通过某一种机制实现线程的串行执行,从而达到线程安全性的目的。
3.自旋锁
尝试获取锁的线程不会阻塞,而是采用死循环的方式去获取锁;
这样做的好处是减少了线程上下文切换的消耗,缺点是死循环很耗CPU。
下面这段是 CAS 自旋锁的源码
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
生活中自旋的例子:一个人饿了到食堂等着开饭;求人办事在别人办公室一直等着别人有空;
4.读写锁/互斥锁
共享锁:即读锁;指该锁可以同时被多个线程持有。
独占锁:即写锁;一次只能被一个线程所持有。ReentrantLock/Synchronized就是独占锁。
互斥锁:
读 - 读 能共存;
读 - 写 不能共存;
写 - 写 不能共存;
读写锁维护了一对锁,一个读锁、一个写锁; 一般情况下,读写锁的性能都会比排它锁好,因为大多数场景读是多于写的。
在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量.
5.分段锁
6.乐观锁/悲观锁
基于乐观锁以及自旋锁来优化了 synchronized 的加锁开销;
同时在重量级锁阶段,通过线程的阻塞以及唤醒来达到线程竞争和同步的目的。
7.偏向锁/轻量级锁/重量级锁
8.独享锁/共享锁