Java并发-重入锁ReentrantLock

基础

  • 重入锁:一个线程对同一个锁资源可以重复获取(如synchronized关键字)
  • ReentrantLock是可重入锁,并且支持获取锁时的公平与非公平选择。
  • ReentrantLock默认为非公平锁,这是出于性能考虑(对于非公平锁,一个刚释放锁的线程很大概率可以再次获得该锁,而不用去排队,减少上下文切换次数)。而公平锁总是会让你到同步队列走一遭,即使你刚释放了锁,然后立马请求锁。即公平锁的实现是以线程切换为代价的。

基本使用

ReentrantLock lock = new ReentrantLock();//非公平锁
//ReentrantLock lock = new ReentrantLock(true);//公平锁
        lock.lock();
        try{
            //to do
        }finally {
            lock.unlock();
        }

ReentrantLock的基本骨架

ReentrantLock implements Lock{
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {......};
static final class NonfairSync extends Sync {};//非公平锁用这个同步器
static final class FairSync extends Sync {};//公平锁用这个同步器
}
public ReentrantLock(boolean fair) {//选择是公平锁还是非公平锁
     sync = fair ? new FairSync() : new NonfairSync();
}
public ReentrantLock() {//默认为非公平锁
        sync = new NonfairSync();
}

源码角度分析其可重入性和公平性的实现

可重入特性实现(非公平锁为例)

锁的获取

如果当前同步状态已经被线程获取(state != 0),判断当前尝试获取同步状态的线程是否是已经获取同步状态的线程,如果是就代表当前线程重入获取锁,将同步状态的值增加(所以获取锁多少次,就应该释放锁多少次),返回成功。

 final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }
锁的释放

因为同步状态的获取可能获取了n次,所以应该只有最后一次释放之后才应该返回true(线程已释放锁)。

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;
        }

公平性实现

用户层面而言:锁的获取严格遵守FIFO模式
源码角度来说:公平锁的tryAcquire与非公平锁不同之处在于---公平锁如果判断锁空闲,还需要去判断同步队列中有没有在排队的(非公平锁没有这一步),如果有的话就去同步队列中排队。

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;
        }

你可能感兴趣的:(Java并发-重入锁ReentrantLock)