Java各种锁的分类以及介绍

锁的分类

之前写过一篇synchronized的文章,这次写下所有涉及到锁。相信大家都知道Java中的锁,可能知道的并不是很全,今天我来给大家详细的分类以及介绍下。

  1. 偏向锁/轻量级锁/重量级锁
  2. 乐观锁/悲观锁
  3. 可重入锁/非可重入锁
  4. 共享锁/独占锁
  5. 自旋锁/非自旋锁
  6. 公平锁/非公平锁
  7. 可中断锁/不可中断锁

锁的介绍

偏向锁/轻量级锁/重量级锁

这三种锁特指synchronized锁的状态,通过对象头中的 MarkWord 来表明锁的状态。一个对象初始化还没有任何线程来获取它的锁时那就是可偏向的。
当有一个线程来访问并尝试获取时,它会将这个线程记录下来。如果以后尝试获取锁的线程正好是偏向锁的拥有者,就可以直接获取锁。

在我们日常开发中synchronized中的代码是被多个线程交替执行的,而不是同时执行的。也就说并不存在实际的竞争。在这种情况下用轻量级锁是可以解决的。
轻量级锁是指当锁原来是偏向锁的时候,被另一个线程访问,说明存在竞争,那么偏向锁会升级成轻量级锁。线程会通过自旋的形式尝试获取锁,从而不会陷入阻塞

重量级锁是互斥锁,利用我们操作系统的同步机制实现的,相对来说开销会比较大。当多个线程直接有实际竞争且锁竞争时间长的时候。
轻量级锁不能满足,锁就会升级成重量级锁。而重量级锁会让拿不到锁的线程进入阻塞状态。

其中偏向锁性能最好,轻量级锁性能中等,重量级锁性能最差

乐观锁/悲观锁

悲观锁在获取资源之前必须先拿到锁,以便达到“独占”的状态。当线程操作资源时,其他线程拿不到锁,从而不会操作其资源
乐观锁恰恰相反,它并不要求在操作资源之前必须拿到锁,而是利用CAS的理念,在不独占资源的情况下,完成对资源的修改。

可重入锁/非可重入锁

可重入锁是指当前线程已经持有了这把锁,能在不释放这把锁的情况下,再次获取这把锁。比如说重入了3次,那在释放锁时也需要释放3次。
不可重入锁是指当前线程虽然持有了这把锁,如果想再次获取这把锁,必须先释放锁之后才能再次尝试获取。

共享锁/独占锁

共享锁指的是我们同一把锁可以被多个线程同时获得,而独占锁只能被一个线程获取。

自旋锁/非自旋锁

自旋锁的理念是如果线程现在拿不到锁,并不直接陷入阻塞或者释放 CPU 资源,而是开始利用循环,不停地尝试获取锁。
非自旋锁的理念就是没有自旋的过程,如果拿不到锁就直接放弃,或者进行其他的处理逻辑,例如去排队、陷入阻塞等。

公平锁/非公平锁

公平锁是指如果线程现在拿不到这把锁,那么线程就都会进入等待,开始排队,在等待队列里等待时间长的线程会优先拿到这把锁。
非公平锁会在一定情况下,忽略掉已经在排队的线程,发生插队现象。

可中断锁/不可中断锁

synchronized关键字修饰的锁代表的是不可中断锁,一旦线程申请了锁,只能等到拿到锁以后才能进行其他的逻辑。
ReentrantLock是一种典型的可中断锁,可使用lockInterruptibly方法在获取锁的过程中,突然不想获取了,可以在中断之后去做其他的事情,不需要一直等到获取到锁才离开。