2015-06-15 4 views
0

Мне было интересно, если кто-то использовал класс java.util.concurrent.Exchanger. Согласно java docs Exchange может использоваться для обмена некоторыми данными между парой для потоков. Нижеприведенный пример является типичным для чтения и записи данных и взаимодействия между потоками.Exchanger Vs CountDownLatch

class FillAndEmpty { 
    Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>(); 
    DataBuffer initialEmptyBuffer = ... a made-up type 
    DataBuffer initialFullBuffer = ... 

    class FillingLoop implements Runnable { 
    public void run() { 
     DataBuffer currentBuffer = initialEmptyBuffer; 
     try { 
     while (currentBuffer != null) { 
      addToBuffer(currentBuffer); 
      if (currentBuffer.isFull()) 
      currentBuffer = exchanger.exchange(currentBuffer); 
     } 
     } catch (InterruptedException ex) { ... handle ... } 
    } 
    } 

    class EmptyingLoop implements Runnable { 
    public void run() { 
     DataBuffer currentBuffer = initialFullBuffer; 
     try { 
     while (currentBuffer != null) { 
      takeFromBuffer(currentBuffer); 
      if (currentBuffer.isEmpty()) 
      currentBuffer = exchanger.exchange(currentBuffer); 
     } 
     } catch (InterruptedException ex) { ... handle ...} 
    } 
    } 

    void start() { 
    new Thread(new FillingLoop()).start(); 
    new Thread(new EmptyingLoop()).start(); 
    } 
} 

То же самое можно было бы сделать с двумя CountDownLatch s. Один для записи в буфер и один для уведомления автора, как только все потоки читателей обработали записи. Так что мой вопрос

  1. Что такое идеальное использование Exchanger
  2. Каковы плюсы и минусы над сказать CountDownLatch
+0

Насколько я могу судить, то, что вы получаете сверху, является гарантией отношения «происходить до», то есть все нитки А, сделанные с обмениваемым объектом, будут видны потоком B и наоборот. И, как следует из названия, он обменивает объекты между потоками, обрабатывая оба направления в одном вызове. Он представляет собой более специализированную, но более высокоуровневую операцию, чем защелка обратного отсчета. – biziclop

+0

Спасибо @biziclop. Я предполагаю, что я могу извлечь из этого, хотя то же самое можно было бы достичь через Latches или Semafhores, Exhangers являются специфическими для такого рода работ, если не проблема в совместном использовании контейнера данных между потоками чтения n читателя. – Tatha

+0

@Taffa Это мое, по крайней мере, на это, но, как отказ от ответственности, я должен сказать, что я никогда не использовал 'Exchanger' в гневе. Там может быть несколько важных деталей, которые я забыл. – biziclop

ответ

0

С CountDownLatches, вы должны поместить ссылки на буферы где-то так, что они доступны для обоих потоков (или передают ссылки на конструкторы). Это увеличивает размер программного кода. Затем вам нужно воссоздать CountDownLatch для каждой транзакции.

Другие подходы:

  • использование пара семафоров вместо CountDownLatches - нужно не воссоздавать
  • использовать пару ArrayBlockingQueues - нужно не воссоздавать, не нужно беспокоиться о ссылках на bufferes, и лучше параллелизма, чем при использовании Exchanger.

UPDT Теплообменник представляет собой пару блокирующих очереди размером 1 каждый, с одной операцией exhange которая эквивалентна queue1.put(value); return queue2.take();. Таким образом, единственный случай, когда его использование оправдано, - это когда вам нужна пара блокирующих очередей размером 1 и всегда звоните и получайте одновременно. Это редкий случай, и я не вижу причины, почему он был включен в стандартную библиотеку java.

+0

Спасибо @Alexei за ваши предложения. Поскольку этот типичный вариант использования может быть реализован многими способами, мне было интересно, есть ли вариант использования, где Exchanger лучше, чем большинство других решений? – Tatha

+3

@Tatha Не стоит недооценивать значение простоты. Теплообменники очень просты и просты в использовании. Недостатком является то, что он решает очень специализированную проблему. – biziclop

0

CountDownLatch - это механизм синхронизации. Вы инициализируете экземпляр фиксированным значением N, а затем ожидаете, пока некоторые другие потоки не уменьшат этот счетчик до 0. Его часто используют, чтобы сделать поток ожидающим завершения других N различных потоков. Но, конечно, есть много других приложений.

Exchanger - это механизм связи. Он позволяет передавать объект из потока T1 в T2 и в то же время передавать объект с T2 на T1. Перемещение блокируется, поэтому вы можете использовать его как механизм синхронизации, но это не то, для чего это предназначено.

Смежные вопросы