您的位置:首页 > 编程语言 > Java开发

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

2011-08-25 15:23 337 查看
     最近在学习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, a
true
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 returned
false
, 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 its
tryAcquireShared(int)

method should return a negative value, if this method returns
true
(unless this is a reentrant acquire).

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

   这篇文章是我在学些xylz文章的时候一点小想法的产物。我还是小菜鸟,需要不断的努力!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息