乐观锁 | 悲观锁
悲观锁和乐观锁是按按并发情况下资源的分配策略区分
乐观锁: 认为对同一数据的并发操作,是不会发生修改的。在进行读取操作是不会上锁,在进行写入操作的时候回判断当前数据是否被修改过。
乐观锁的实现方案:版本号机制和 CAS 机制 (CAS 机制需要解决 ABA 问题)。
悲观锁:认为对于同一数据的并发操作,一定会发生修改,哪怕没发生修改,也会认为修改。即最坏的情况总是会发生。
悲观锁在持有数据的时候总会把资源或数据锁上,这样其他线程想要请求这个资源的时候就会阻塞,直到悲观锁把资源释放为止。
乐观锁适用于读多写少的场景;悲观锁适用于写多读少的场景。
公平锁 | 非公平锁
公平锁和非公平锁是按照锁的获取顺序来区分
公平锁:指多线程下按照线程申请锁的顺序来分配锁。即先来先得顺序。
非公平锁:指多线程下获取锁的顺序不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。
因为公平锁需要额外的资源来记录线程的请求顺序,所以非公平锁的性能要比公平锁好
独享锁 | 共享锁
独享锁和共享锁是按照可持有锁的线程数来区分
独享锁:指该锁一次只能被一个线程持有。
共享锁:指该锁可以被多个线程持有。
独享锁与共享锁是通过 AQS 来实现的,通过实现不同的方法,来实现独享或者共享。
互斥锁 | 读写锁
互斥锁和读写锁其实就是独享锁和共享锁的具体说法。
互斥锁在 Java 中的实现就是 ReentrantLock,读写锁在 Java 中的实质就是 ReadWriteLock
偏向锁 | 轻量级锁 | 重量级锁
这三种锁是指锁的状态,针对
Synchronized
偏向锁:指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价。
轻量级锁:指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式常识获取锁,不会阻塞,提高性能。
重量级锁:指当锁为轻量级锁的时候,另一线程虽然是自旋,单自旋不是无限持续下去的,当自选达到一定次数后,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
其他:自旋锁 | 可重入锁 | 分段锁
自旋锁:指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁
自旋锁的好处是减少线程上下文切换的消耗,缺点是循环会消耗
CPU
。
可重入锁:又名递归锁。指同一个线程在外层方法获取锁的时候在进入内层方法会自动获取锁,可重入锁可以在一定程度避免死锁。Java 中 Synchronized
和 ReentrantLock
都是可重入锁。
分段锁:是一种锁的设计,并不是具体的一种锁。Java 中 ConcurrentHashMap
中的 Segment
使用的分段锁设计。