队列的同步
我一直在阅读Doug Lea的“Java中的并发编程”一书。 您可能知道,Doug最初编写了Java Concurrency API。 但是,有些事情使我感到困惑,我希望就这个小难题获得一些我的看法!
从Doug Lea的排队示例中获取以下代码...
class LinkedQueue {
protected Node head = new Node(null);
protected Node last = head;
protected final Object pollLock = new Object();
protected final Object putLock = new Object();
public void put(Object x) {
Node node = new Node(x);
synchronized (putLock) { // insert at end of list
synchronized (last) {
last.next = node; // extend list
last = node;
}
}
}
public Object poll() { // returns null if empty
synchronized (pollLock) {
synchronized (head) {
Object x = null;
Node first = head.next; // get to first real node
if (first != null) {
x = first.object;
first.object = null; // forget old object
head = first; // first becomes new head
}
return x;
}
}
}
static class Node { // local node class for queue
Object object;
Node next = null;
Node(Object x) { object = x; }
}
}
这是一个相当不错的队列。 它使用两台显示器,因此生产者和消费者可以同时访问队列。 太好了! 然而,'last'和'head'的同步让我很困惑。 该书指出这是队列目前或将要有0个条目的情况所需要的。 好吧,够公平的,这是有道理的。
然而,然后我看着Java Concurrency LinkedBlockingQueue。 队列的原始版本在头部或尾部不同步(我也想发布另一个链接到现代版本,它也遭受同样的问题,但我不能这样做,因为我是一个新手)。 我想知道为什么不呢? 我在这里错过了什么吗? 是否存在我缺少的Java内存模型的某些特殊性质? 我会想到可见性的目的,这种同步是必要的? 我会感谢一些专家意见!
在版本中,您将链接以及最新JRE中的版本放在一起,Node类中的项目是volatile的,它强制读写所有其他线程都可见,这里是一个更深入的解释。http:// www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
这里的微妙之处是synchronized(null)会抛出一个NullPointerException,所以head和last都不允许为空。 它们都被初始化为永远不会从任一列表返回或删除的相同虚拟节点的值。
put()和poll()在两个不同的锁上同步。 如果这些方法可以修改来自不同线程的相同值,那么这些方法需要在同一个锁上进行同步,以保证线程安全。 这是一个问题的唯一情况是当头==最后(即它们是同一个对象,通过不同的成员变量引用)。 这就是代码在头部和尾部同步的原因 - 大多数情况下,这些都是快速,不受约束的锁,但偶尔头和尾会是同一个实例,其中一个线程将不得不阻止另一个。
可见性问题的唯一时间是队列几乎为空时,其余时间put()和poll()在队列的不同端工作,并且不会相互干扰。
链接地址: http://www.djcxy.com/p/44985.html上一篇: Synchronization of a Queue
下一篇: How can I use other/more modern schema validation with .Net?