Reentranlock FairSync NonFairSync

本文详细探讨了ReentrantLock的工作原理及其与Synchronized的区别。主要分析了非公平锁NonfairSync与公平锁FairSync的实现机制,包括它们的lock方法、tryAcquire方法等关键部分。

 

对于Reentranlock的用法,对比Synchronized多了 定时守候、可中断守候、公平和非公平。本文重点就Reentranlock 中的代码实现做一个分析。而对于其与Synchronize 区别可参考下文。

可以参考深入研究 Java Synchronize 和 Lock 的区别与用法http://my.oschina.net/softwarechina/blog/170859

 FairSync NonFairSync  两者都是java.util.concurrent包中同步类中如Semaphere,Reentranlock 等类中的内部类,两者继承自 AQS,而Reentranlock中的 两者代码如下所示,为独占模式。两者都实现了tryAcquire,与lock方法。

101628_Cq4b_2834932.png

 

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

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

Reentranlock 根据参数,确定使用哪种同步器,默认是NonFairSync。从代码分析出,NonFairSync最大的特点是,调用lock时,会先尝试去获取资源,而获取不同,则通过父类的acquire(1)方法,调用各自子类的tryAcquire方法,如下。而对于NonFairSync,在一次执行父类Sync中的方法,在一次尝试获取资源。

然而对于FairSync的lock,直接调用acquire,少了一次直接获取的过程,接着调用子类的tryAcquire方法,当有资源空闲时,并不像NonFair 直接尝试get,而是先判断当前线程是否队列头部的线程,或者是空的queue,则尝试获取。否则判断当前线程是否是占用资源的线程。如果是,则将state+1,表示该线程调了多次lock,释放时要调同等次数的unlock,才能释放资源。


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

        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() &&  //当前Thread是否是head节点的next节点线程,因为公平的锁,按顺序获取资源
                    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;
        }
    }

    接着上一步,两者都没有获取到资源时,将执行一样的流程,但是执行到tryAcqure方法时,会根据不同子类实现的来执行。

        如下代码,首先

  1.     addWaiter,,生成一个Exclusive模式的结点,并将当前结点加入到queque的尾部。如果原tail为null,也就是queque为null时,会cas一个new  Node,而后加到该node尾部。并做为新的tail。
  2.     而后会 执行acquireQueued方法,根据node的 predocessor,判断是否为head,如果是则执行tryAcquire,  获取成功后,将当前结点置为head,并将thread置为null,已经获得资源。
  3.    当node的prddocessor不为head时,或者获取失败,接着会根据waitStatus,执行相关操作,最终state置为Node.Signal,而后被阻塞,等着被unPark或者被中断。
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

 

而对于 Reentranlock 的其它功能如 中断守候,超时等,都是针对这些条件做了额外的操作。

转载于:https://my.oschina.net/ovirtKg/blog/740918

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值