Java 1.7 ReentrantLock源码解析

 

1.   简介

    可重入锁是基于AQS实现的,和synchronized有相同的语义,同时有更多的扩展功能,比如可以tryLock和在指定时间内获取锁、响应中断获取锁等。典型用法如JDK 1.7中的示例:

lock.lock();  // block until condition holds
 *     try {
 *       // ... method body
 *     } finally {
 *       lock.unlock()
 *     }

  有两种模式:公平模式和非公平模式。公平和非公平的的含义见Java1.7 ReentrantReadWriteLock源码解析,类结构图如下所示:

Java 1.7 ReentrantLock源码解析_第1张图片

主类ReentrantLock就一个sync成员变量,借助其实现lock/unlock功能。

2.   ReentrantLock

2.1 lock

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

lock函数实现synchronized语义:1、如果当前没有线程占有锁,立即返回,设置独占标识且state值设置为1;2、如果当前线程已经占有锁了,立即返回,设置state+=1;3、如果其他线程已经占有锁了,当前线程会一直等待,直到获取到锁。

2.2    unlock

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

tryLock函数释放锁,如果当前线程占有锁,则设置state-=1,减1后如果state为0了,则清空独占线程标识(setExclusiveOwnerThread(null));如果当前线程没有占有锁就调用unlock方法,则抛出异常IllegalMonitorStateException。

2.3    lockInterruptibly

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

lockInterruptibly函数实现了synchronized语义,但是支持中断(当其他线程调用了interrupt方法)。

2.4    tryLock

public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

tryLock函数尝试获取锁(不管公平模式还是非公平模式都不排队)。如果锁已经被其他线程获取了直接返回false,否则,返回true。

2.5    带超时的tryLock

public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

和2.4上面的不同,这个支持中断且在公平模式下是要排队的。如果当前没有线程获取到锁,直接返回true,否则,等待直至超时或被中断。如果不想排队又想要支持超时,你可以这么写:if(lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }

2.6   getHoldCount

public int getHoldCount() {
        return sync.getHoldCount();
    }

 getHoldCount函数返回当前线程重入锁了几次(也有可能是0)。

1.   Sync

3.1 nonfairTryAcquire

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
// 如果没有线程占有锁且设置state成功,则设置线程独占标识并返回true
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
// 如果是重入的,设置state+=acquires并返回true(如果int没越界)
            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;
        }

  nonfairTryAcquire函数尝试获取锁,不排队方式,如果当前没有线程占有锁或者是重入的,返回true;否则,返回false。

3.2 tryRelease

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;
// 如果state==0了,清空线程独占标识
                setExclusiveOwnerThread(null);
            }
// 肯定是占有锁了,不用循环CAS了,直接设置
            setState(c);
            return free;
        }

 tryRelease函数释放锁,如果state为0了,则要清空线程独占标识。

4.   NonfairSync

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * 先插个队尝试获取锁(大多数情况会成功的),如果失败了再调用tryAcquire
         * 里面会考虑重入的情况。
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
// 可以直接插队获取锁的且会考虑重入情况
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

5.   FairSync

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * 公平模式下获取锁的方式,如果state==0且前面没有线程排队才能获取锁;
         * 或者是重入的情况。
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
// c==0且前面没有线程排队且CAS设置成功,则设置线程独占标识,返回true
                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;
        }
    }


你可能感兴趣的:(java,并发,锁,ReadWriteLock,juc)