队列的同步

gem*_*rix 7 java concurrency

我一直在阅读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; }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是一个非常好的队列.它使用两个监视器,因此Producer和Consumer可以同时访问Queue.太好了!但是,'last'和'head'上的同步让我感到困惑.该书指出,对于Queue当前或即将有0个条目的情况,这是必需的.好吧,公平,这种做法很有道理.

但是,然后我查看了Java Concurrency LinkedBlockingQueue.队列的原始版本不会在头部或尾部同步(我也想发布另一个链接到现代版本,它也遇到同样的问题,但我不能这样做因为我是新手).我想知道为什么不呢?我在这里错过了什么吗?是否缺少Java内存模型特殊性质的某些部分?为了可见性,我会考虑需要这种同步吗?我很欣赏一些专家意见!

Yan*_*mon 2

在您提供链接的版本以及最新 JRE 中的版本中,Node 类内的项目是易失性的,它强制读取和写入对所有其他线程可见,这里有更深入的解释 http: // www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile