Reentranlock FairSync NonFairSync

 

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

能够参考深刻研究 Java Synchronize 和 Lock 的区别与用法http://my.oschina.net/softwarechina/blog/170859node

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

 

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中的方法,在一次尝试获取资源。ui

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

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方法时,会根据不一样子类实现的来执行。线程

        以下代码,首先code

  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 的其它功能如 中断守候,超时等,都是针对这些条件作了额外的操做。orm

相关文章
相关标签/搜索