ReentrantLock源码+图深度解析呀


  java除了使用关键字 synchronized外,还可以使用 ReentrantLock实现独占锁的功能。而且 ReentrantLock相比 synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。这篇文章主要是从使用的角度来分析一下 ReentrantLock

简介

  ReentrantLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。

  1. synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
  2. synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。
  3. synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

  ReentrantLock好像比synchronized关键字没好太多,我们再去看看synchronized所没有的,一个最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

源码解析

  RetrantLock有两种实现方式,一种是公平锁,一种是非公平锁,如字面意思,公平锁也就是在等待队列中等待时间越长的Thread 拥有优先获取锁的资格,而非公平锁则不一样,每一次有线程释放锁之后,哪个线程取得锁是不可预期的,但这个不代表着随机线程获取锁。可以从源码的角度来分析;

abstract static class Sync extends AbstractQueuedSynchronizer {

        private static final long serialVersionUID = -5179523762034025860L;

        // 抽象方法,获取锁
        abstract void lock();

        //以非公平的方式获取锁
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //没有线程获取锁,直接获取锁,并设置为当前线程独占
            if (c == 0) (
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //当前线程已经获取了锁,再次获取锁,执行+aquires操作
            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 tryRelease(int releases) {
            int c = getState() - releases;
            //释放锁时,线程不一致,抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        .......
    }

  Sync类是ReentrantLock的一个类,继承自AbstractQueuedSynchronizer,用于管理获取锁和释放锁;Sync实现了以非公平的方式。Sync有两个子类,分别是NonfairSyncFairSync,我们来看源码:

/**
     * 非公平锁,非公平锁中释放锁后,等待队列中获取锁的线程是不可预知的。但这不代表着随机。
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * 如果state为0,获取锁,将当前线程设置为独占线程,否自进入循环队列,不断获取锁acquire(1)
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        //以非公平的方式尝试获取锁
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
/**
     * 公平锁
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        //以公平的方式获取锁,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;
        }
    }

  对比UnfairSyncFairSynctryAcquire(int acquires)方法,其中UnfairSync会去做判断hasQueuedPrecessors(),如果队列中还有前置节点,当前线程就不会获取锁,因此保证了先进入队列的线程会先获取锁,因此被称为公平锁。而非公平锁没有此判断,获取锁失败后,会进入队列,不断尝试获取锁。

图解公平锁与非公平锁

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值