Java多线程(4)ReentrantLock详解

上一篇:Java多线程(3) wait、notify 详解

ReentrantLock详解

一. 什么是ReentrantLock

1. 介绍ReentrantLock

ReentrantLock称为重入锁,它有公平锁和非公平锁两种实现方式,比内部锁synchonized拥有更强大的功能,它可中断、可定时、设置公平锁
使用ReentrantLock时,一定要释放锁,一般释放放到finnal里写

JAVA的java.util.concurrent框架中提供了ReentrantLock类(于JAVA SE 5.0时引入),ReentrantLock实现了lock接口,具体在JDK中的定义如下:

public class ReentrantLock implements Lock, java.io.Serializable {
 public ReentrantLock() {
        sync = new NonfairSync();
    }
    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
}

看到一个类首先就需要知道它的构造方法有哪些,ReentrantLock有两个构造方法,一个是无参的 ReentrantLock() ;另一个含有布尔参数public ReentrantLock(boolean fair)。后面一个构造函数说明ReentrantLock可以新建公平锁;而Synchronized只能建立非公平锁。

ReentranckLock内部有三个内部类,分别是:

  • Sync:继承了AbstractQueuedSynchronizer(AQS)同步器的内部类,来实现同步机制的
    Sync是继承了AbstractQueuedSynchronizer的内部抽象类,主要由它负责实现锁的功能。它内部存在一个获取锁的等待队列及其互斥锁状态下的int状态位(0当前没有线程持有该锁、n存在某线程重入锁n次),该状态位也可用于其它诸如共享锁、信号量等功能
    Sync在ReentrantLock中有两种实现类:NonfairSync、FairSync,正好对应了ReentrantLock的非公平锁、公平锁两大类型
  • FairSync:公平锁对象
  • NonfairSync:非公平锁对象

公平锁和非公平锁在获取锁的区别在于:

  • 公平锁获取锁的时候,进入排队(先入先得)。源码如下图:
    在这里插入图片描述
  • 非公平锁线尝试插队,如果插队不成功再进行排队。源码如下图:
    在这里插入图片描述

2. ReentrantLock和synchronized的异同点

  • ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区。但是实现上两者不同:synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活。一般并发场景使用synchronized的就够了;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。
  • ReentrantLock和synchronized都是可重入的。synchronized因为可重入因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;而ReentrantLock在重入时要却确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。
  • synchronized是基于JVM层面实现的,而Lock是基于JDK层面实现的。曾经反复的找过synchronized的实现,可惜最终无果。但Lock却是基于JDK实现的,我们可以通过阅读JDK的源码来理解Lock的实现
  • ReentrantLock具有更好的细粒度,可以在ReentrantLock里面设置内部Condititon类,可以实现分组唤醒需要唤醒的线程
  • RenentrantLock能实现公平锁

二. 重入锁

重入锁(递归锁)指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,可以理解为:同一个线程函数获得锁之后,内层递归函数依然能够获取到该锁对象的代码,也即,在同一个线程的外层方法访问的时候,获取到了锁,在进入内层方法后能够自动获取到锁。线程可以进入任何一个它已经拥有的锁所同步着的代码块

线程再次获取锁:所需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次获取成功
锁的最终释放:线程重复n次获取了锁,随后在第n次释放该锁后,其它线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前线程被重复获取的次数,而被释放时,计数自减,当计数为0时表示锁已经成功释放

猜你喜欢

转载自blog.csdn.net/haiyanghan/article/details/109316115