- 浏览: 478653 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
龘龘龘:
TrueBrian 写道有个问题,Sample 1中,为了控制 ...
What's New on Java 7 Phaser -
龘龘龘:
楼主总结的不错。
What's New on Java 7 Phaser -
TrueBrian:
有个问题,Sample 1中,为了控制线程的启动时机,博主实际 ...
What's New on Java 7 Phaser -
liguanqun811:
不知道楼主是否对zookeeper实现的分布式锁进行过性能测试 ...
Distributed Lock -
hobitton:
mysql的get lock有版本限制,否则get lock可 ...
Distributed Lock
Inside AbstractQueuedSynchronizer (1)
Inside AbstractQueuedSynchronizer (2)
Inside AbstractQueuedSynchronizer (3)
Inside AbstractQueuedSynchronizer (4)
3.4 Template Method
AbstractQueuedSynchronizer提供了以下几个protected方法用于子类改写
protected boolean tryAcquire(int arg) protected boolean tryRelease(int arg) protected int tryAcquireShared(int arg) protected boolean tryReleaseShared(int arg) protected boolean isHeldExclusively()
这几个方法的默认实现是抛出UnsupportedOperationException,子类可以根据需要进行改写。
AbstractQueuedSynchronizer中最基本的acquire流程的相关代码如下:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
如果tryAcquire失败,那么当前线程可能会被enqueue到WaitQueue,然后被阻塞。 shouldParkAfterFailedAcquire方法会确保每个线程在被阻塞之前,其对应WaitQueue中的节点的waitStatus被设置为Node.SIGNAL(-1),以便在release时避免不必要的unpark操作。此外shouldParkAfterFailedAcquire还会清理WaitQueue中已经超时或者取消的Node。需要注意的是,在某个线程最终被阻塞之前,tryAcquire可能会被多次调用。
AbstractQueuedSynchronizer中最基本的release流程的相关代码如下:
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); }
release方法中,总是总head节点开始向后查找sucessor。只有当该sucessor的waitStatus被设置的情况下才会调用unparkSuccessor。unparkSuccessor方法中首先清除之前设置的Node.waitStatus,然后向后查找并且唤醒第一个需要被唤醒的sucessor。需要注意的是,if (s == null || s.waitStatus > 0)这个分支中,查找是从tail节点开始,根据prev引用向前进行。在Inside AbstractQueuedSynchronizer (2) 中提到过,Node.next为null并不一定意味着没有sucessor,虽然WaitQueue是个双向链表,但是根据next引用向后查找sucessor不靠谱,而根据prev引用向前查找predecessor总是靠谱。
3.5 Fairness
到目前为止我们已经知道,WaitQueue是个FIFO的队列,唤醒也总是从head开始。但是AbstractQueuedSynchronizer却并不一定是公平的(实际上,大多数情况下都是在非公平模式下工作)。如果在看一遍acquire方法会发现,tryAcquire的调用顺序先于acquireQueued,也就是说后来的线程可能在等待中的线程之前acquire成功。这种场景被称为barging FIFO strategy,它能提供更高的吞吐量。
大多数AbstractQueuedSynchronizer的子类都同时提供了公平和非公平的实现,例如ReentrantLock提供了NonfairSync和FairSync。例如其FairSync的tryAcquire方法如下:
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; }
tryAcquire方法返回true的条件之一是!hasQueuedPredecessors() 。hasQueuedPredecessors的代码如下:
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()); }
综上, FairSync优先确保等待中线程先acquire成功。但是公平性也不是绝对的:在一个多线程并发的环境下,就算锁的获取是公平的,也不保证后续的其它处理过程的先后顺序。
既然默认情况下使用的都是NonfairSync,那么FairSync适合什么样的场景呢?如果被锁所保护的代码段的执行时间比较长,而应用又不能接受线程饥饿(NonfairSync可能会导致虽然某个线程长时间排队,但是仍然无法获得锁的情况)的场景下可以考虑使用FairSync。对于ReentrantLock,在其构造函数中传入true,即可构造一把公平锁。
评论
* SIGNAL: The successor of this node is (or will soon be)
* blocked (via park), so the current node must
* unpark its successor when it releases or
* cancels. To avoid races, acquire methods must
* first indicate they need a signal,
* then retry the atomic acquire, and then,
* on failure, block.
int ws = pred.waitStatus; if (ws == Node.SIGNAL)//下次循环判断 返回true block线程 /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { /* * waitStatus must be 0 or PROPAGATE. Indicate that we * need a signal, but don't park yet. Caller will need to * retry to make sure it cannot acquire before parking. */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//第一次设置,标志需要这样一个信号 } return false;
发表评论
-
Understanding the Hash Array Mapped Trie
2012-03-30 10:36 0mark -
Atomic Bit Operation in Linux Kernel
2012-02-08 00:27 1979Linux Kernel支持atomic bit operat ... -
A Hierarchical CLH Queue Lock
2012-01-14 19:01 2110A Hierarchical CLH Queue Lock ( ... -
Inside AbstractQueuedSynchronizer (4)
2012-01-08 17:06 3464Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (2)
2012-01-07 17:54 6304Inside AbstractQueuedSynchroniz ... -
Inside AbstractQueuedSynchronizer (1)
2012-01-06 11:04 7888Inside AbstractQueuedSynchroniz ... -
Code Optimization
2011-10-14 00:11 1558当前开发人员在进行编码的时候,可能很少关注纯粹代码级别的优化了 ... -
Distributed Lock
2011-08-02 22:02 91321 Overview 在分布式系统中,通常会 ... -
What's New on Java 7 Phaser
2011-07-29 10:15 81411 Overview Java 7的并 ... -
Sequantial Lock in Java
2011-06-07 17:00 21661 Overview Linux内核中常见的同步机 ... -
Feature or issue?
2011-04-26 22:23 121以下代码中,为何CglibTest.intercept ... -
Bloom Filter
2010-10-19 00:41 50191 Overview Bloom filt ... -
Inside java.lang.Enum
2010-08-04 15:40 64041 Introduction to enum J ... -
Open Addressing
2010-07-07 17:59 33951 Overview Open addressi ... -
JLine
2010-06-17 09:11 10949Overview JLine 是一个用来处理控 ... -
ID Generator
2010-06-14 14:45 1633关于ID Generator,想 ... -
inotify-java
2009-07-22 22:58 82081 Overview 最近公 ... -
Perf4J
2009-06-11 23:13 84301 Overview Perf4j是一个用于计算 ... -
Progress Estimator
2009-02-22 19:37 1485Jakarta Commons Cookbook这本书 ... -
jManage
2008-12-22 00:40 39141 Overview 由于项目需要, 笔者开发了一个 ...
相关推荐
Allegro自带的ODB++inside工具下载,ODB++inside插件可以将Allegro的.brd文件转化为仿真工具Hyperlynx使用的文件。共6个文件,需要分别下载。 ODB_Inside_Cadence_Allegro_111_Windows_64_SA_Setup.zip.001 ODB_...
Inside C++ Object Model/Inside C++ Object Model/Inside C++ Object Model/Inside C++ Object Model
Allegro自带的ODB++inside工具下载,ODB++inside插件可以将Allegro的.brd文件转化为仿真工具Hyperlynx使用的文件。共6个文件,需要分别下载。 ODB_Inside_Cadence_Allegro_111_Windows_64_SA_Setup.zip.001 ODB_...
Allegro自带的ODB++inside工具下载,ODB++inside插件可以将Allegro的.brd文件转化为仿真工具Hyperlynx使用的文件。共6个文件,需要分别下载。 ODB_Inside_Cadence_Allegro_111_Windows_64_SA_Setup.zip.001 ODB_...
Inside_NAND_Flash_Memories.pdf
Inside the C++ Object Model 中文版
inside ole 英文版,还是英文版看着舒服!inside ole 英文版,还是英文版看着舒服!inside ole 英文版,还是英文版看着舒服!inside ole 英文版,还是英文版看着舒服!inside ole 英文版,还是英文版看着舒服!...
I-BUS Inside Inside the BMW Cars entertainement Serial Bu
Inside_NAND_Flash_Memories全面讲解NAND FLASH
Inside JVM
本工具是为了方便 将C/C++ 结构体自动生成 C# 结构,方便大家编码 微软官方下载地址已经不可用了,我找寻了很久,为了下载花了不下百元,现在我上传来 给大家减负。
MS Press - Inside ATL PDF document
Inside the C++ Object Model focuses on the underlying mechanisms that support object-oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, ...
Allegro自带的ODB++inside工具下载,ODB++inside插件可以将Allegro的.brd文件转化为仿真工具Hyperlynx使用的文件。共6个文件,需要分别下载。 ODB_Inside_Cadence_Allegro_111_Windows_64_SA_Setup.zip.001 ODB_...
Inside Bluetooth Low Energy (Mobile Communications) By 作者: Naresh Gupta ISBN-10 书号: 1630810894 ISBN-13 书号: 9781630810894 Edition 版本: 2nd ed. Release 出版日期: 2016-06-30 pages 页数 (458)
c++ book inside com development
200dpi扫描 超清晰 Dale Rogerson写的Inside COM是COM(组件对象模型)的唯一经典书籍,Inside COM这本书是我最喜爱的书,也是启蒙我的书,用词幽默简单,这本书可以让程序员建立起大强的软件模型的观念,透过研究COM...
文档是PlayDead公司在制作Inside游戏时用的渲染技术,英文好的朋友可以下来看看!
Inside COM 中文版 電子書 非掃描