显示锁——ReentrantLock 原理探究

5 篇文章 0 订阅

显示锁——ReentrantLock 原理探究

java中有两种锁:内置锁和显示锁。内置锁是JVM管理的锁,由synchronized关键字开启,但是它是一个非公平锁。显示锁是可以由java程序员自己控制的锁像本次要介绍的可重入锁:ReentrantLock,它可以设置成一个公平锁。具体原来如何,最近看了下源码,顺便记录下源码所得。

AQS

先简单介绍下显示锁的代码结构,ReentrantLock(后面简称RL)内部维护了一个内部类:Sync,源码见下面的

 abstract static class Sync extends AbstractQueuedSynchronizer {
	.......
	.......
  }

内部类Sync 继承的 AbstractQueuedSynchronizer 就是我们平常经常说到的AQS。AQS 源码太多,这里就不贴了,简单来说就是,它维护了一个双向链表在其内部,这个链表有什么用?到时候下面讲公平锁的实现时在会知道。这里放下双向链表的源码:

static final class Node {
     
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

      
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

Sync

Sync有什么用?来看下RL的加锁和解锁方法:

public class ReentrantLock implements Lock, java.io.Serializable {
 	
    private final Sync sync;

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

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

由上面源码可知,RL的加锁和解锁实际上调用的都是Sync的加锁和解锁方法。但是,Sync 是抽象类,那他必然有实现类,没错,在RL里,Sync有两个实现类:
NonfairSyncFairSync

NonfairSync

非公平锁,RL默认构造的是非公平锁

    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

NonfairSync的实现原理是通过java的CAS去获取锁,如何获取不到就会放到双向链表里,下面是它的源码:

    /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {

        /**
         * 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);
        }
    }

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }

FairSync

公平锁,通过构造函数指定构建公平锁:

    /**
     * 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();
    }

和非公平锁类似,也是通过java的CAS去完成加锁,不同的是,公平锁每次获取锁的线程都会拿链表头的线程优先获取锁,两种锁tryAcquire方法的不同完成不同的加锁方式。下面是源码:


  /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        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;
        }
    }

    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order	
        Node h = head;
        Node s;
	// 链表头
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

可重入锁

通过研究tryAcquire方法我们可以看到,RL的锁状态是通过其内部的一个volatile 修饰的state参数进行标志的,当通一个线程多次调用tryAcquire 方法,state会加上acquires(RL中是1),解锁的时候会减去acquires,加了几次锁,在释放的时候就要减去几次,这就是RL的可重入锁的由来。


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

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        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) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值