Синхронизация очереди

Я читал на 'Программировании параллелизма Doug Lea в Java' книгу. Как можно знать, Doug первоначально записал Параллелизму Java 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; }
  }
}

Это вполне хорошая Очередь. Это использует два монитора так Производитель, и Потребитель может получить доступ к Очереди одновременно.Мило! Однако синхронизация на 'последнем' и 'главном' смущает меня здесь. Книга указывает, что это необходимо для для ситуации, посредством чего Очередь в настоящее время или собирающийся иметь 0 записей. Хорошо, достаточно ярмарка и это отчасти имеют смысл.

Однако затем я посмотрел на Параллелизм Java LinkedBlockingQueue. Исходная версия Очереди не синхронизируется на голове или хвосте (я также хотел отправить другую ссылку на современную версию, которая также страдает от той же проблемы, но я не мог сделать так, потому что я - новичок). Интересно почему нет? Я пропускаю что-то здесь? Есть ли некоторая часть особенной природы Модели памяти Java, которую я пропускаю? Я думал бы в целях видимости, что эта синхронизация необходима? Я ценил бы некоторые мнения эксперта!

7
задан skaffman 27 February 2010 в 12:23
поделиться

2 ответа

В версии, на которую вы разместили ссылку, а также в последней версии JRE, элемент внутри класса Node является изменчивым, что обеспечивает выполнение операций чтения и записи в быть видимым для всех других тем, вот более подробное объяснение http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile

2
ответ дан 7 December 2019 в 14:31
поделиться

Тонкость здесь в том, что synchronized (null) вызовет исключение NullPointerException, поэтому ни head, ни last не могут стать нулевыми. Оба они инициализируются значением одного и того же фиктивного узла, который никогда не возвращается и не удаляется ни из одного списка.

put () и poll () синхронизируются на двух разных блокировках. Методы должны будут синхронизироваться на одной и той же блокировке, чтобы быть потокобезопасными по отношению друг к другу, если они могут изменять одно и то же значение из разных потоков. Единственная ситуация, в которой это является проблемой, - когда head == last (т.е. это один и тот же объект, на который ссылаются через разные переменные-члены). Вот почему код синхронизируется на head и last - в большинстве случаев это будут быстрые, неконтролируемые блокировки, но иногда head и last будут одним и тем же экземпляром, и один из потоков должен будет блокировать другой.

Единственный раз, когда видимость является проблемой, - это когда очередь почти пуста, а остальное время put () и poll () работают на разных концах очереди и не мешают друг другу.

2
ответ дан 7 December 2019 в 14:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: