Java中锁的分类
一、介绍
在Java
中的锁可以分为以下这四类
- 可重入锁、不可重入锁
- 乐观锁、悲观锁
- 公平锁、非公平锁
- 互斥锁、共享锁
二、详解
1)可重入锁、不可重入锁
当一个线程持有一个锁后,又想再持有这个锁时,发生的情况。
- 可重入锁:允许再次持有,多少次都没问题。
- 不可重入锁:不允许再次持有,已经持有了锁后,再次去获取时,会造成死锁的情况。
没必要给自己增加负担,所以Java
中的锁基本都是可重入锁
2)乐观锁、悲观锁
他们两之间的区别主要体现在访问资源时,要不要进行上锁
- 乐观锁:假定多个线程同时访问同一个资源时,并不会彼此产生干涉和冲突,因此在多线程并发时,每个线程都可以自由访问共享资源,只在更新时检查数据是否被其他线程修改。如果数据未被修改,乐观锁会直接进行更新。常见的乐观锁实现包括版本号机制和CAS机制。
Java
中的Atomic
相关的类,底层正是使用的CAS
。 - 悲观锁:每个线程在访问,都要先进行上锁,这样其他线程就无法访问。悲观锁适用于对数据更新操作比较频繁的场景。当锁被别人占用时,线程只能进入等待阻塞阶段了。在
Java
中,synchronized
和Lock
相关的类都属于悲观锁。
他们主要的区别是,由于悲观锁会造成锁的占用和线程的切换,故占用较大。而乐观锁,发现数据、版本号不对时,就会放弃此次操作,重新再一次进行读写,占用不大,适合比较小量的线程共享数据。
如果只是少量的操作,那么进行乐观锁即可。
如果是大批的操作,一大批的线程共享数据,那么进行悲观锁会好上很多。
3)公平锁、非公平锁
公平锁和非公平锁主要的区别在于获取锁时的排队机制不同。
当一个A线程正在运行,B线程先来阻塞,C后来阻塞,那么A线程运行完后,B线程和C线程如何进行分配
- 公平锁:遵循先入先出,先到先得的策略,对线程进行分配。
- 非公平锁:不管先来后到,线程统一进行竞争,有
CPU
调度进行分配。
Java
中的synchronized
就是一款非公平锁,而Lock
锁两者皆可,是可以进行设置的。
4)互斥锁、共享锁
线程持有锁后,其他线程同时持有这把锁,通过这样的特性进行区分
- 互斥锁:不同的线程不能同时持有同一把锁
- 共享锁:不同的线程允许同时持有同一把锁
在Java
中,synchronized
关键字就是一把互斥锁,而读写锁ReadWriteLock
中的读锁,就是一个共享锁。
三、最后
我是半月,你我一同共勉!!!