1.乐观锁&悲观锁
主要是从对加锁的态度上来考虑
如果感觉锁竞争并不激烈,就会用到乐观锁
如果感觉锁竞争会很激烈,就会用到悲观锁
2.轻量级锁&重量级锁
这俩关注的是加锁的过程
轻量级加锁的实现相对简单,主要依赖Java层面的指令(用户态),资源消耗较低。
重量级加锁的实现相对复杂,主要依赖内核态的操作,资源消耗较高
乐观锁是一种形式的轻量级锁,因为能不加锁就没加,节省了资源
悲观锁是一种形式 的重量级锁,因为他任何时间都加了锁
3.自旋锁&挂起等待锁
自旋锁:就是在用户态的情况下,不断地循环问锁是否被释放,以便第一时间就能用到资源
挂起等待锁:阻塞等待,被唤醒才去用
优缺点
自旋锁 :是纯用户态的操作,能第一时间获得锁,来节约调用系统的资源,有自旋次数以及时间的限制,如果在这个限制内就等大节约了资源
挂起等待锁 : 是内核态的操作,直接加锁生成阻塞等待,被唤醒再运行,阻塞过程中会释放cpu资源
4.读写锁&互斥锁
读写锁又被分为读锁和写锁
读锁可以同时很多读锁一起运行,使用读锁能增加多线程环境下的运行效率
写锁只能一个写锁运行,与其他的锁是冲突的
所以,写锁不能与读锁共存,写锁也不能和写锁共存,读锁能和读锁共存
为什么要用读写锁?
在程序运行过程中,并不是所有的操作都需要修改数据的,但是我们有希望读数据的时候不要修改数据,读与写不能同时进行时加锁
当写操作时,不希望任何线程来读数据,当写完之后才能继续对数据进行读取,就可以加写锁
普通互斥锁
有竞争关系,只能一个线程释放锁之后,其他线程才可以抢,写锁就属于互斥锁
5.公平锁&不公平锁
公平锁就是按顺序,排队进行,我们知道,公平是需要代价的,所以要消耗更多资源
不公平锁就是大家去抢,谁抢到是谁的
6.可重入锁&不可重入锁
可重入锁:对一把锁可以多次加,不会造成死锁
不可重入锁: 对一把锁可以多次加,会造成死锁
synchronized是什么锁
7.自旋锁原理 cas
cas 全名为 compare and swap 字面意思则为 比较和交换
在 Java 中,有一个Unsafe
类,它在sun.misc
包中。它里面都是一些native
方法,其中就有几个是关于 CAS 的:
boolean compareAndSwapObject(Object o, long offset,Object expected, Object x);
boolean compareAndSwapInt(Object o, long offset,int expected,int x);
boolean compareAndSwapLong(Object o, long offset,long expected,long x);
当我们点开这些方法时就会发现底层的实现带有native,说明是c++实现的 ,更加类似于一种指令,将比较和修改在硬件层面进行了,所以虽然看起来是两步操作,但是在Java层面,是一步操作,类似于指令,而指令是一定是原子性的,这样就相比较于synchronized,节约了锁资源,cas在底层层面相当于一个cmpxchg指令
cas中有一个预期值,每次得到结果都会与预期值比较,若比较值与预期值相等了,就会进行下一步操作

cas的ABA问题
ABA问题就是当我们想要从A改为C时,有人提前将A改为了B再改为了A,此时,在我们的视角下A并未改变,于是我们将A改为了C,但是由于A受到了两次改变,于我们预想的不一致,于是我们在cas中就会加入一个预期值,每次改变都会使预期值来改变,确保准确