Java中的AQS在Java6和Java7中的一点小不同

     最近在学习xylz博客中关于Java Concurrency部分。看到了其中的AQS部分,就在Eclipse中查看了这个类的源码。正好我同时装了Jdk6和Jdk7,所以想看看在Jdk7中有没有进行改变。在看到ReentrantLock.FairSync.tryAcquire是发现这里有点不同了。

     ps:为了避免因版本不同而可能导致的混淆,先说下我的版本。jdk 1.7.0 build1.7.0-b147、jdk1.6.0_22 build1.6.0_22-b04。

    tryAcquire(int) : 试图在独占模式下获取对象状态。此方法应该查询是否允许它在独占模式下获取对象状态,如果允许,则获取它。

    这个方法总是由执行acquire的线程来调用。如果此方法报告失败,则acquire方法可以将线程加入队列(如果它还没有加入队列),直到获得其他某个线程释放了该线程的信号。也就是说此方法是一种尝试性的方法,如果成功获取锁那最好,没有成功也没关系,直接返回False.

    以下是tryAcquire(int)两个Jdk版本的源码对比:

Java6:

/**
         * 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 (isFirst(current) &&
                    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;
        }
Java7:

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

    if(c==0)之后的判断就是这两份代码中不同的地方了,这里我只注意到了方法名不同,如果其他方法的签名相同但是实现变了,就没那么明显了。不过我相信不会有这么2的做法的。这里标红的部分主要是要判断当前线程是否在AQL的CHL队列的头或者这个队列是否为空。如果当前线程是CHL队列的头或者队列是空的,就执行compareAndSetState(int, int)方法。

  以下是isFirst和hasQueuedPredecessors的源码:

/**
     * Return {@code true} if the queue is empty or if the given thread
     * is at the head of the queue. This is reliable only if
     * <tt>current</tt> is actually Thread.currentThread() of caller.
     */
    final boolean isFirst(Thread current) {
        Node h, s;
        return ((h = head) == null ||
                ((s = h.next) != null && s.thread == current) ||
                fullIsFirst(current));
    }

      isFirst方法会首先判断队列是否为空,为空就返回true。不为空就判断下一个节点,看当前的线程是否是队列在队列的头。不过在这里可能有个会混淆的地方,就是这里使用 head.next.thread 来进行判断的,看起来使用队列的第二个节点来进行比较的。这里就要知道队列的节点AbstractQueuedSynchronizer.Node对象了。Node是一个对列的节点,入队操作调用的是Node.enq(Node)方法。当第一次调用这个操作时会初始化一个空的Node对象作为队列的头结点,所以实际上的头节点应该是队列的第二个节点。如果这里快捷的比较不成功的话,只能遍历节点找出头结点了。这里就调用了fullsFirst(Thread)方法。以下是fullsFirst(Thread)的方法:

 final boolean fullIsFirst(Thread current) {
        // same idea as fullGetFirstQueuedThread
        Node h, s;
        Thread firstThread = null;
        if (((h = head) != null && (s = h.next) != null &&
             s.prev == head && (firstThread = s.thread) != null))
            return firstThread == current;
        Node t = tail;
        while (t != null && t != head) {
            Thread tt = t.thread;
            if (tt != null)
                firstThread = tt;
            t = t.prev;
        }
        return firstThread == current || firstThread == null;
    }
    fullsFirst方法会首先在判断一次head.next.thread == thread,如果成功就返回,失败就进行遍历。

-----------------------------------------------------------------------------------------------------------------------------------

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

     hasQueuedPredecessors方法就简单多了。这里要注意一点,该方法返回true相当于isFirst返回false。这个方法的本意是看是否有比当前线程等待更久的线程。有就返回true,也就是说该方法返回true,tryAcquire就必须返回false。如果该方法返回false,说明没有线程比当前线程等待的更久,所以当前线程是队列的头结点。

      isFirst和hasQueuedPredecessors的主要区别是比较的时候isFisrt和fullsFirst都是用的在tryAcquire中通过调用Thread.currentThread()得到的对象,而hasQueuedPredecessors在比较时才会调用Thread.currentThread()。

   在hasQueuedPredecessors的javadoc中说道:

          Note that because cancellations due to interrupts and timeouts may occur at any time, atrue return does not guarantee that some other thread will acquire before the current thread. Likewise, it is possible for another thread to win a race to enqueue after this method has returnedfalse, due to the queue being empty.

    从这里可以看出,这个方法并不保证什么。

    This method is designed to be used by a fair synchronizer to avoidbarging.Such a synchronizer's tryAcquire(int) method should return false, and itstryAcquireShared(int) method should return a negative value, if this method returnstrue (unless this is a reentrant acquire).

    这其中红色部分的说明可能是hasQueuedPredecessors取代isFirst方法的原因。但是这个barging具体是什么意思我也不知道。希望大家能够给我提供解答!


   这篇文章是我在学些xylz文章的时候一点小想法的产物。我还是小菜鸟,需要不断的努力!!!!









评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值