RTL(ReentrantLock) 学习笔记

什么是ReentrantLock 及其作用

ReentrantLock 基于 AQS(AbstractQueuedSynchronized),在并发编程中它可以实现公平锁非公平锁来对资源进行同步,同时和synchronized一样,ReentrantLock支持可重入。ReentrantLock在调度上更灵活,支持更多丰富的功能。

可重入性

在并发编程中可重入性指的是 单个线程重新进入同一个子程序仍然是线程安全的 。一个线程可以不用释放而重复获取某个锁n次,只是在释放时需要相应释放n次。
死锁:若A线程既获取了锁,又在等待自己释放锁就会造成死锁。

公平锁 & 非公平锁

  • 非公平锁:不按照请求锁的顺序分配,不一定拥有获取锁的机会,但性能可能比公平锁高。
  • 公平锁:按照请求锁的顺序分配,拥有锁的机会稳定,但性能可能比非公平锁低。

Lock接口定义

RTL 实现了Lock接口,而Lock定义了6个方法,这6个方法定义了一些广泛的操作边界。

  • void Lock()方法:获取锁,加入当前锁被其他线程占用,则等待直到获取为止。
  • void lockInteruptibly() throws InterruptedException;方法:获取锁,假如当前线程在等待锁的过程中被中断,那么会退出等待,并抛出中断异常。
  • boolean tryLock(); 尝试获取锁,并立即返回,返回值代表的是是否成功获取到锁。
  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 在一段时间内尝试获取锁,假如期间被中断,则抛出中断异常。
  • void unlock(); 释放锁。
  • Condition newCondition(); 新建一个绑定在当前Lock上的Condition对象。
    Conditon对象,表示一个等待状态, 获得锁的线程在某些时刻需要等待一些条件的完成才能继续执行,可以通过await()方法注册在Condition上进行等待,然后通过Condition方法的signal()方法将其唤醒。一个Lock对象可以关联多个Condition,多个线程可以被绑定到不同的Condition上,就可以分组唤醒。Condition还提供了和限时/中断相关的功能,丰富了线程的调度策略。

RTL三个核心内部类Sync & NonfairSync & FairSync

Sync

abstract static class Sync extends AbstractQueuedSynchronizer {...}
  • RTL内部类Sync继承了AQS,说明AQS中所有预设的机制Sync都可以使用.
  • abstract 修饰Sync内部类,说明Sync需要通过其子类来进行实例化。NonfairSync和FairSync是Sync唯二的两个子类。

NonfairSync

非公平锁的具体实现

  • NonfairSync的具体实现中,Lock()方法内上来直接插队,先进行两次非公平的获取锁,若这两次获取锁失败,那么将进入FIFO队列进行排队直到获取锁。
  • 而tryAquire方法则是进行一次插队尝试获取锁,如果确实不想排队,那么上层可以写个循环不断调用这个方法尝试插队获取锁。
    /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

FairSync

公平锁的具体实现

  • lock()方法直接调用AQS的acquire()方法
  • tryAcquire()实现AQS接口,若当前线程已经获取锁,则对state值进行累加操作,可以继续使用锁,实现可重入。若锁一开始是空闲的,那么允许直接拿锁,若不空闲判断累加或者直接入队排号。
    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        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;
        }
    }

RTL 的构造函数

ReentrantLock有两个构造函数

  • 默认无参构造函数使用了非公平锁的模式
  • 含参构造函数 可以自由选择使用公平锁还是非公平锁实现。
  • 一旦初始化就不能更改。因为RTL的属性Sync使用final修饰,一旦初始化就不可修改引用。
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync; // 私有变量使用final修饰
    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    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();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值