Java多线程系列(七)—ReentrantLock源码分析

Java多线程系列(七)—ReentrantLock源码分析

ReentrantLock是一个可重入的互斥锁,在一个时间点只能被被一个线程持有,同时可重入的特性又异味着一把锁能够被同一个线程多次获取;同时ReentrantLock又分为公平锁和非公平锁,公平锁下线程排队依次获取锁,非公平锁机制下在锁是可获取的情况下不管自己是否在队列头都会获取锁;

个人主页:tuzhenyu’s page
原文地址:Java多线程系列(七)—ReentrantLock源码分析

ReentrantLock实例

public class Depot {
    private int capacity;
    private int size;

    private final Lock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();

    public Depot(int capacity){
        this.capacity = capacity;
        size = 0;
    }

    public void produce(){
        lock.lock();
        try {
            while (size>=capacity)
                notFull.await();
            size++;
            System.out.println("生产者生产一个,当前数量为:"+size);
            notEmpty.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    public void consume(){
        lock.lock();
        try {
            while (size<=0)
                notEmpty.await();
            size--;
            System.out.println("消费者消费一个,当前数量为:"+size);
            notFull.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}

ReentrantLock源码分析

(0) ReentrantLock类结构

  • ReentrantLock类中包含着Sync、NonfairSync、FairSync三个类,其中Sync类是一个静态抽象类继承AbstractQueuedSynchronized类,NonfairSync与FairSync类继承自Sync类是公平锁和非公平锁的具体实现;

  • ReentrantLock锁的实现基础是底层的AQS,通过AQS实现具体的锁功能

(1) ReentrantLock类的初始化

  • ReentrantLock实例化时默认是创建非公平锁,非公平锁在高并发的情况下具有更高的性能,因为非公平锁可以减少上下文的切换;
public ReentrantLock() {
    sync = new NonfairSync();
}
  • 在创建ReentrantLock实例的的时候可以通过参数制定创建公平锁或者非公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

(2) ReentrantLock类的的常用方法

  • ReentrantLock类的lock()方法是通过调用公平锁或者非公平锁实例的lock方法实现
public void lock() {
    sync.lock();
}
  • ReentrantLock类的unlock()方法是通过简介调用AQS同步器的release()方法实现的
public void unlock() {
    sync.release(1);
}
  • ReentrantLock类创建Condition是通过创建ConditionObject类实例,ConditionObject类实例中包含FirstWaiter和lastWaiter指针用来保存线程节点单向链表;
final ConditionObject newCondition() {
    return new ConditionObject();
}
  • ReentrantLock类的await()方法和signal()方法是通过调用ConditionObject实例的await()方法或者signal()方法

(3) 公平锁

  • 公平锁的加锁执行流程
  • 公平锁的lock()方法会调用AQS同步器的acquire()方法尝试获取锁
final void lock() {
    acquire(1);
}
  • 在AQS的require()方法中会调用acqire()方法尝试获取锁,如果获取失败则将线程阻塞放入同步队列
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
  • 在线程尝试获取锁的时候,FairSync类的tryRequire()方法会判断当前锁状态是否被占用(state),如果没被占用并且同步队列中没有等待的线程(!hasQueuedPredecessors())才会持有该锁,否则阻塞进入同步队列的尾部;
 protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

(4) 非公平锁

  • 非公平锁的执行流程
  • 非公平锁的lock()方法在被调用时会先通过compareAndSetState()方法尝试获取锁,获取失败后才会调用AQS的require()方法再次进行锁的尝试获取;
final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
  • 在AQS的require()方法中会调用acqire()方法尝试获取锁,如果获取失败则将线程阻塞放入同步队列
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
  • 在线程尝试获取锁的时候,NonFairSync类的tryRequire()方法会直接尝试获取锁,不会判断阻塞队列中是否存在阻塞排队线程;
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

(5) 公平锁和非公共锁的区别

  • 在执行lock()方法时,非公平锁会直接尝试获取锁,获取失败后才会执行AQS的acquire()方法

非公平锁

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

公平锁


final void lock() {
    acquire(1);
}
  • 在tryRequire()方法执行时,公平锁会检查同步队列中是否存在阻塞的线程,如果有则阻塞加入到同步队列尾部;非公平锁在执行tryRequire()方法时不会检查是否存在排队线程直接尝试获取;

非公平锁

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

公平锁

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

总结

  • ReentrantLock锁机制的实现是基于AQS同步器,主要是实现了FairSync公平锁和NonfairSync非公平锁;

  • 公平锁和非公平锁的区别在于公平锁的线程执行严格按照AQS中的同步队列的排队顺序,非公平锁的线程在加锁时会尝试获取锁不会检查同步队列是否存在排队线程;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值