Java中锁的分类

一、介绍

Java中的锁可以分为以下这四类

  1. 可重入锁、不可重入锁

  2. 乐观锁、悲观锁

  3. 公平锁、非公平锁

  4. 互斥锁、共享锁

二、详解

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中的读锁,就是一个共享锁。

三、最后

我是半月,你我一同共勉!!!