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:
if(c==0)之后的判断就是这两份代码中不同的地方了,这里我只注意到了方法名不同,如果其他方法的签名相同但是实现变了,就没那么明显了。不过我相信不会有这么2的做法的。这里标红的部分主要是要判断当前线程是否在AQL的CHL队列的头或者这个队列是否为空。如果当前线程是CHL队列的头或者队列是空的,就执行compareAndSetState(int, int)方法。
以下是isFirst和hasQueuedPredecessors的源码:
isFirst方法会首先判断队列是否为空,为空就返回true。不为空就判断下一个节点,看当前的线程是否是队列在队列的头。不过在这里可能有个会混淆的地方,就是这里使用 head.next.thread 来进行判断的,看起来使用队列的第二个节点来进行比较的。这里就要知道队列的节点AbstractQueuedSynchronizer.Node对象了。Node是一个对列的节点,入队操作调用的是Node.enq(Node)方法。当第一次调用这个操作时会初始化一个空的Node对象作为队列的头结点,所以实际上的头节点应该是队列的第二个节点。如果这里快捷的比较不成功的话,只能遍历节点找出头结点了。这里就调用了fullsFirst(Thread)方法。以下是fullsFirst(Thread)的方法:
-----------------------------------------------------------------------------------------------------------------------------------
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
a race to enqueue after this method has returned
从这里可以看出,这个方法并不保证什么。
This method is designed to be used by a fair synchronizer to avoidbarging.Such
a synchronizer's
method should return a negative value, if this method returns
这其中红色部分的说明可能是hasQueuedPredecessors取代isFirst方法的原因。但是这个barging具体是什么意思我也不知道。希望大家能够给我提供解答!
这篇文章是我在学些xylz文章的时候一点小想法的产物。我还是小菜鸟,需要不断的努力!!!!
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
truereturn 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文章的时候一点小想法的产物。我还是小菜鸟,需要不断的努力!!!!
相关文章推荐
- 菜鸟发现的java7和java6中一点的不同
- Java6的@override注解与Java5不同之处
- java 命令模式详解,敢不敢稍微不同一点
- Java 与PHP 在正则表达式匹配上的一点小不同
- java6的@override注解与java5的不同之处
- Java5、Java6、Java7的新特性
- java5、java6、java7的新特性
- Java5、Java6、Java7的新特性
- 转帖 java6的@override注解与java5的不同之处 收藏
- Java5、Java6、Java7的新特性
- java6的@override注解与java5的不同之处
- 实际操作发现的java中if位置不同引起的一点变化
- Java6的@override注解与Java5不同之处
- 详解Java5、Java6、Java7的新特性
- Java5、Java6、Java7的新特性
- python和java不同的地方
- Java与C/C++不同的一些基础知识点
- Java 语言程序设计 变化不同颜色和大小的字符串
- Java中不同数字类型之间的转换
- Java5 java6 新特性