读书人

Inside AbstractQueuedSynchronizer (

发布时间: 2012-09-03 09:48:39 作者: rapoo

Inside AbstractQueuedSynchronizer (2)

Inside AbstractQueuedSynchronizer (1)

Inside AbstractQueuedSynchronizer (2)

Inside AbstractQueuedSynchronizer (3)

Inside AbstractQueuedSynchronizer (4)

?

3 AbstractQueuedSynchronizer

?

3.1 Inheritance

??? AbstractQueuedSynchronizer继承自AbstractOwnableSynchronizer。AbstractOwnableSynchronizer继承自Object并且实现了Serializable接口,它只有一个成员变量private transient Thread exclusiveOwnerThread以及对应的getter/setter方法。该成员变量用于保存当前拥有排他访问权的线程。需要注意的是,该成员变量没有用volatile关键字修饰。


3.2 State

??? AbstractQueuedSynchronizer用一个int(private volatile int state)来保存同步状态,以及对应的getter/setter/compareAndSetState方法。Java6新增了一个AbstractQueuedLongSynchronizer,它用一个long来保存同步状态,貌似目前没有被java.util.concurrent中的其它synchronizer所使用。对于ReentrantLock,state为0则意味着锁没有被任何线程持有;否则state保存了持有锁的线程的重入次数。

?

3.3 WaitQueue

??? WaitQueue是AbstractQueuedSynchronizer的核心,它用于保存被阻塞的线程。它的实现是"CLH" (Craig, Landin, and Hagersten) lock queue的一个变种。

?

??? 标准的CLH lock queue通常被用来实现spin lock,它通过TheadLocal变量pred引用队列中的前一个节点(Node本身没有指向前后节点的引用),以下是标准的CLH lock queue的一个参考实现:

private void setHead(Node node) {    head = node;    node.thread = null;    node.prev = null;}

? ? setHead方法没有用到锁,也没有使用CAS,这样没有并发问题?没有,因为这个方法只会被持有锁的线程所调用,此时只需要将head指向持有锁的线程对应的node即可。

?

1 楼 lixieinstein 2012-05-03 您好,看的您的文章很受启发。
但是有一点不太理解,请问ClhSpinLock中的ThreadLocal<Node> pred有什么作用呢?
在lock时可以通过tail来获取前任节点,然后判断其状态来决定是否自选等待,那为什么还需要一个本地线程的pred来储存前任节点呢?在unlock时,只需要将当前节点的locked状态修改为false就可以释放后继结点,this.node.set(this.pred.get()); 貌似没有实质性的作用呀? 2 楼 yxs_815 2012-05-21 lixieinstein 写道您好,看的您的文章很受启发。
但是有一点不太理解,请问ClhSpinLock中的ThreadLocal<Node> pred有什么作用呢?
在lock时可以通过tail来获取前任节点,然后判断其状态来决定是否自选等待,那为什么还需要一个本地线程的pred来储存前任节点呢?在unlock时,只需要将当前节点的locked状态修改为false就可以释放后继结点,this.node.set(this.pred.get()); 貌似没有实质性的作用呀?
和 lixieinstein 的想法一致,感觉用AtomicReference<Node> pred, 就行了,连ThreadLocal<Node> node都没必要吧? 这样锁的实现应该不可以重入。 3 楼 lixieinstein 2012-05-23 yxs_815 写道lixieinstein 写道您好,看的您的文章很受启发。
但是有一点不太理解,请问ClhSpinLock中的ThreadLocal<Node> pred有什么作用呢?
在lock时可以通过tail来获取前任节点,然后判断其状态来决定是否自选等待,那为什么还需要一个本地线程的pred来储存前任节点呢?在unlock时,只需要将当前节点的locked状态修改为false就可以释放后继结点,this.node.set(this.pred.get()); 貌似没有实质性的作用呀?
和 lixieinstein 的想法一致,感觉用AtomicReference<Node> pred, 就行了,连ThreadLocal<Node> node都没必要吧? 这样锁的实现应该不可以重入。
谢谢回复,:D ,不可以重入,如果要重入就要判断当前线程是否持锁线程,然后还要对加锁次数和释放锁次数进行操作。这个例子让我对CLH队列有了很好的理解,呵呵

读书人网 >编程

热点推荐