ReentrantLock源码分析

       ReentrantLock比Synchronized提供了更加灵活的加锁方式,可中古段一个正则等待锁的线程,实现指定时间的获取锁,实现公平与非公平锁等。

构造器及lock()

    //默认构造非公平同步器
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    //可构造公平或非公平同步器
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    //根据相应的同步器使用不同的获取锁的方式
    public void lock() {
        sync.lock();
    }
    
    //非公平式
    final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
    
    //公平式
    final void lock() {
            acquire(1);
        }

     非公平锁和公平锁,都继承自ReentrantLock的静态内部类Sync,Sync继承自AQS。

      每一个ReentrantLock都持有这一个Sync,根据构造方式的不同,Sync分别对应着公平锁和非公平锁。当ReentrantLock调用lock()方法进行加锁时,会根据持有的Sync的不同去调用不同的加锁方式。

      如果是公平锁,线程将按照它们发出请求的顺序来获得锁,但在非公平锁上,则允许插队行为:当一个线程请求非公平的锁时,如果在发出请求的同时该锁的状态变为可用,那么这个线程将跳过队列中所有等待的线程直接获得这个锁。

     

 static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        //获取锁
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

Sync默认实现非公平锁,主要看看它的获取锁和释放锁的实现。

获取锁的步骤:

1、 获取当前线程以及锁的同步状态。

2、 如果同步状态为0,表示锁没有被占用,用CAS的方式设置当前线程为锁的拥有者(非公平式)。

3、 如果同步状态不为0,且当前线程是锁的拥有者,则同步状态增加(加1);如果同步状态不为0,且当前线程不是锁的拥有者,则获取锁失败。

释放锁的步骤:

1、同步状态减1。

2、如果当前线程不是锁的拥有者,则抛出异常。否则,执行3.

3、如果同步状态为0,表示当前线程不在占有锁,将锁的占有线程设为null;如果同步状态不为0,则更新同步状态。

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        //非公平式获取锁
        @ReservedStackAccess
        final boolean nonfairTryAcquire(int acquires) {
            //获取当前线程
            final Thread current = Thread.currentThread();
            //获取同步状态
            int c = getState();
            //同步状态为0 锁没有被占用
            if (c == 0) {
                //CAS设置同步状态
                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;
        }

        @ReservedStackAccess
        protected final boolean tryRelease(int releases) {
            //同步状态减值
            int c = getState() - releases;
            //如果当前线程不是独占锁拥有者
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            //为0表示当前线程释放释放了锁,该锁自由了
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            //更新同步状态
            setState(c);
            return free;
        }
    }

对于公平式锁,获取锁的步骤:

1、获取当前线程及锁的同步状态。

2、如果同步状态为0,表示锁没有被其他线程占有。先查询同步队列中是否有其他线程在排队(公平式获取),如果没有,则用CAS的方式设置同步状态,当设置成功后,设置当前线程为锁的占有者。

3、如果同步状态不为0,则

     3.1 当前线程是锁的占有者,则获得锁,更新同步状态

     3.2 当前线程不是锁的占有者,获取失败。

 //公平的同步器
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        @ReservedStackAccess
        protected final boolean tryAcquire(int acquires) {
            //获取当前线程
            final Thread current = Thread.currentThread();
            //获得同步状态
            int c = getState();
            //没有线程占有锁
            if (c == 0) {
                //如果没有前驱结点
                /**
                 * 这时和非公平锁不同的是它会先去调用hasQueuedPredecessors方法查询同步队列
                 * 中是否有人在排队,如果没人在排队才会去修改同步状态的值,可以看到公平锁在
                 * 这里采取礼让的方式而不是自己马上去获取锁。除了这一步和非公平锁不一样之外,
                 * 其他的操作都是一样的。
                 */
                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;
        }
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值