ReentrantLock源码---JDK1.8


可重入锁实现:给每一个锁关联一个获取计数值和一个所有者线程
非公平锁:抢占式,直接尝试修改state,获取锁
公平锁:先检查同步等待队列是否有等待的线程,先来先得

//构造函数,默认是非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }

 //指定策略
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

 

先看看Sync这个类,继承自AQS:(因为默认是非公平模式,所以这里直接实现了非公平模式下的尝试获取锁)

  //非公平模式尝试获取锁
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //c=0,说明当前没有线程获取锁,CAS尝试设置state,获取锁
                if (compareAndSetState(0, acquires)) {
                    //抢占成功,将当前线程设置为独占模式
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //到这里,说明锁已经被持有,检查持有锁的线程是否为当前线程
            else if (current == getExclusiveOwnerThread()) {
                //如果是,累加重入次数
                int nextc = c + acquires;
                //小于0 ,超过int的最大值了
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
               //设置state
                setState(nextc);
                return true;
            }
            //如果锁已经被抢占,并且持有线程不是当前线程,返回false。
            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) {
                //c=0,释放完毕,
                free = true;
                //解除所有者关系
                setExclusiveOwnerThread(null);
            }
            //设置重入次数
            setState(c);
            return free;
        }

 

看看子类NonfairSync 非公平锁的实现:
final void lock() {
            //非公平锁,抢占模式,CAS直接尝试设置state,获取锁。
            if (compareAndSetState(0, 1))
                //获取成功,将当前线程设置为所有者
                setExclusiveOwnerThread(Thread.currentThread());
            else
                //CAS失败,在独占模式下请求。
                acquire(1);
        }
        //非公平锁,尝试请求
        protected final boolean tryAcquire(int acquires) {
            //直接调用父类方法
            return nonfairTryAcquire(acquires);
        }

再看看子类FairSync 公平锁的实现:

 

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

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        //公平锁的tryAcquire()。
        //只有在递归(重入)或者同步队列中没有其他线程
        //或者当前线程是等待队列中的第一个线程时,才允许访问。
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //如果c=0,说明锁没有被持有,需要检查同步等待队列中
                //是否有其他线程,如果没有,尝试设置state
                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");
                //设置state
                setState(nextc);
                return true;
            }
            return false;
        }

 

整理一下大概逻辑:

 

加锁操作:

非公平:
1.直接CAS抢占设置state,如果成功,获取锁成功。
2.如果获取失败,需要检查锁是否被其他线程持有
3.如果没有其他线程持有锁,会以CAS的方式尝试获取锁,
,如果成功,获取锁成功。
4.如果有其他线程持有锁,会检查一下持有锁的线程是否为当前线程
如果是,累加重入次数。

公平:
1.会先检查锁是否被其他线程持有,并且检查同步等待队列里有没有其他线程
2.如果没有其他线程持有锁,且同步等待队列里面没有其他线程,会以CAS的方式
尝试获取锁,CAS成功,获取锁成功。
3.如果有其他线程持有锁,检查是否为当前线程,如果是
累加重入次数,获取锁成功。


解锁操作:
1.当前线程先将重入次数减1,如果结果为0,将当前同步器的线程
信息清空,并唤醒同步等待队列中队列头的等待线程
2.如果重入次数减1后结果不为0(说明当前线程还持有当前锁),方法结束


posted @ 2017-11-07 21:01  emoji的博客  阅读(171)  评论(0编辑  收藏  举报