JUC源码简析 ReentrantLock

相关阅读

简介

支持重进入的独占锁,使用内部持有的Sync类型的实例实现了Lock接口。
内部类Sync继承自AbstractQueuedSynchronizer,重写了父类的tryReleaseisHeldExclusively方法;定义抽象方法lock(),由子类实现;
内部类FairSync继承自Sync,以公平(先到先得)竞争锁的方式实现了lock()算法字节;
内部类NonfairSync继承自Sync,以非公平(不保证先到先得)竞争锁的方式实现了lock()算法细节;

源码简析

内部类——Sync

简介

重写了父类的tryReleaseisHeldExclusively方法;
定义抽象方法lock(),由子类实现;

abstract void lock();

tryRelease

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    // 校验释放锁的线程是否时持有锁的线程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        // 当前线程不是持有独占锁的线程,那么就是非法操作,需要抛出IllegalMonitorStateException
        throw new IllegalMonitorStateException();
    // 释放锁标识,默认未释放
    boolean free = false;
    if (c == 0) {
        // 资源为0,则表示本线程已释放锁
        free = true;
        // 清空持有锁线程信息
        setExclusiveOwnerThread(null);
    }
    // 更新锁资源
    setState(c);
    return free;
}

本方法只支持被持有独占锁的线程调用,所以不存在线程竞争,其它线程调用则会抛出异常IllegalMonitorStateException

isHeldExclusively

protected final boolean isHeldExclusively() {
    // 持有锁的线程是否是本线程
    return getExclusiveOwnerThread() == Thread.currentThread();
}

nonfairTryAcquire

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 如果当前锁资源还未被占用
    if (c == 0) {
        // CAS尝试获取锁资源,存在多线程竞争
        if (compareAndSetState(0, acquires)) {
            // 获取成功,设置本线程为持有锁线程
            setExclusiveOwnerThread(current);
            // true表示获取锁成功
            return true;
        }
    }
    // 锁资源已经被占用,则考虑是不是被自身占有的
    else if (current == getExclusiveOwnerThread()) {
        // 可重入的体现

        // 累加锁资源计数
        int nextc = c + acquires;
        if (nextc < 0)
            // 资源计数发生反转,需要抛出错误
            throw new Error("Maximum lock count exceeded");
        // 更新锁资源
        setState(nextc);
        // true表示获取锁成功
        return true;
    }
    // false表示获取锁成功
    return false;
}

本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL,然后挂起,等待新线程释放锁时唤醒自身;

内部类——NonFairSync

简介

继承自Sync,实现非公平锁相关操作;
需要实现的方法为:

  1. 父类Sync的抽象方法lock
  2. 来自父类Sync继承的AbstractQueuedSynchronizer的抽象方法tryAcquire

lock

final void lock() {
    // CAS尝试获取独占锁,即假设锁资源还未被获取,然后占取锁资源
    if (compareAndSetState(0, 1))
        // 获取成功,设置本线程为持有锁线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 老老实实地获取锁
        acquire(1);
}

tryAcquire

protected final boolean tryAcquire(int acquires) {
    // 调用父类Sync的nonfaireTryAcquire实现
    return nonfairTryAcquire(acquires);
}

本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试快速获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL,然后挂起,等待新线程释放锁时唤醒自身;新线程尝试快速获取锁失败后,才老实地按照正常方式去获取锁;

内部类——FairSync

简介

继承自Sync,实现公平锁相关操作;
需要实现的方法为:

  1. 父类Sync的抽象方法lock
  2. 来自父类Sync继承的AbstractQueuedSynchronizer的抽象方法tryAcquire

lock

final void lock() {
    // 老老实实地获取锁,没有尝试快速获取锁
    acquire(1);
}

tryAcquire

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 如果当前锁资源还未被占用
    if (c == 0) {
        // 不存在等待获取锁的线程,才CAS尝试获取锁资源,存在多线程竞争
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            // 获取成功,设置本线程为持有锁线程
            setExclusiveOwnerThread(current);
            // true表示获取锁成功
            return true;
        }
    }
    // 锁资源已经被占用,则考虑是不是被自身占有的
    else if (current == getExclusiveOwnerThread()) {
        // 可重入的体现

        // 累加锁资源计数
        int nextc = c + acquires;
        if (nextc < 0)
            // 资源计数发生反转,需要抛出错误
            throw new Error("Maximum lock count exceeded");
        // 更新锁资源
        setState(nextc);
        // true表示获取锁成功
        return true;
    }
    // false表示获取锁成功
    return false;
}

// AbstractQueuedSynchronizer
public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    // 头节点就是尾节点,则队列没有其它等待节点
    // 队列存在节点,且
    //     头节点的next不存在,即此时有新节点插入队列,刚更新尾节点,还未来得及更新旧尾节点的next,那么队列中存在其它等待节点(新节点)
    //     或者存在但不是本线程,那么队列中有其它等待节点
    // 否则,不存在其它等待节点,因为头节点的next就是本线程节点,这是等待队列中的节点线程尝试获取锁的情况
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

本方式是以公平竞争锁的方式实现的,公平的体现为:新线程在尝试获取锁之前,会先考虑当前是否已存在其它线程在等待获取锁,如果存在则直接放弃获取锁;如果不存在,才尝试获取锁;

ReentrantLock

简介

实现了Lock接口,Lock接口的相关方法都是通过内部类Sync的实例实现;

构造方法

public ReentrantLock() {
    // 默认是非公平锁,使用场景更多
    sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

Lock接口

public void lock() {
    sync.lock();
}

public void unlock() {
    sync.release(1);
}

public Condition newCondition() {
    return sync.newCondition();
}

测试

Demo

public class Demo {
    private int parties = 5;
    private ReentrantLock reentrantLock = new ReentrantLock();


    public static void main(String[] args) throws InterruptedException {
        Demo demo = new Demo();
        ExecutorService es = Executors.newFixedThreadPool(demo.parties);

        for (int i = 0; i < demo.parties; i++) {
            es.execute(new ReentrantLockTask(i, demo.reentrantLock));
        }
        es.shutdown();
    }


    private static class ReentrantLockTask implements Runnable {

        private ReentrantLock reentrantLock;
        private int index;


        ReentrantLockTask(int index, ReentrantLock reentrantLock) {
            this.reentrantLock = reentrantLock;
            this.index = index;
        }

        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(5);
                System.out.println("Thread:" + index + " waits to get lock");
                reentrantLock.lock();
                System.out.println("Thread:" + index + " has get lock");

                TimeUnit.SECONDS.sleep(5);
                reentrantLock.unlock();
                System.out.println("Thread:" + index + " has released lock");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果

Thread:0 waits to get lock
Thread:3 waits to get lock
Thread:2 waits to get lock
Thread:4 waits to get lock
Thread:1 waits to get lock
Thread:0 has get lock
Thread:0 has released lock
Thread:2 has get lock
Thread:2 has released lock
Thread:3 has get lock
Thread:3 has released lock
Thread:1 has get lock
Thread:1 has released lock
Thread:4 has get lock
Thread:4 has released lock
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值