2008-10-08 4 views
80

Есть ли какие-либо преимущества использованияCountDownLatch против Семафор

java.util.concurrent.CountdownLatch

вместо

java.util.concurrent.Semaphore?

Насколько я могу сказать следующие фрагменты почти эквивалентны:

1. Семафор

final Semaphore sem = new Semaphore(0); 
for (int i = 0; i < num_threads; ++ i) 
{ 
    Thread t = new Thread() { 
    public void run() 
    { 
     try 
     { 
     doStuff(); 
     } 
     finally 
     { 
     sem.release(); 
     } 
    } 
    }; 
    t.start(); 
} 

sem.acquire(num_threads); 

2: CountDownLatch

final CountDownLatch latch = new CountDownLatch(num_threads); 
for (int i = 0; i < num_threads; ++ i) 
{ 
    Thread t = new Thread() { 
    public void run() 
    { 
     try 
     { 
     doStuff(); 
     } 
     finally 
     { 
     latch.countDown(); 
     } 
    } 
    }; 
    t.start(); 
} 

latch.await(); 

исключением того, что в случае # 2 защелка не может быть повторно использована и, что более важно, вам нужно знать заранее ho w будет создано множество потоков (или до тех пор, пока все они не будут запущены до создания защелки.)

Итак, в какой ситуации предпочтительнее защелка?

ответ

92

Крышка CountDown часто используется для полной противоположности вашему примеру. Как правило, у вас будет много потоков, блокирующих «ожидание()», которые будут запускаться одновременно, когда счетчик достигнет нуля.

final CountDownLatch countdown = new CountDownLatch(1); 
for (int i = 0; i < 10; ++ i){ 
    Thread racecar = new Thread() {  
     public void run() { 
     countdown.await(); //all threads waiting 
     System.out.println("Vroom!"); 
     } 
    }; 
    racecar.start(); 
} 
System.out.println("Go"); 
countdown.countDown(); //all threads start now! 

Вы также можете использовать это как MPI-стиль «барьер», который вызывает все темы ждать другие потоки ловить до определенной точки, прежде чем продолжить.

final CountDownLatch countdown = new CountDownLatch(num_thread); 
for (int i = 0; i < num_thread; ++ i){ 
    Thread t= new Thread() {  
     public void run() { 
     doSomething(); 
     countdown.countDown(); 
     System.out.printf("Waiting on %d other threads.",countdown.getCount()); 
     countdown.await();  //waits until everyone reaches this point 
     finish(); 
     } 
    }; 
    t.start(); 
} 

Что все сказано, защелка CountDown можно безопасно использовать так, как показано в вашем примере.

+0

Спасибо. Таким образом, мои два примера не были бы эквивалентны, если бы несколько потоков могли ждать на защелке ... если sem.acquire (num_threads); следует sem.релиз (NUM_THREADS) ;? Я думаю, что это сделает их эквивалентными. – finnw 2008-10-08 21:27:37

+0

В некотором смысле, да, до тех пор, пока каждый поток называется приобретением, за которым следует релиз. Строго говоря, нет. С защелкой все потоки могут запускаться одновременно. С помощью семафора они становятся доступными один за другим (что может привести к различному планированию потоков). – 2008-10-08 21:38:46

0

CountdownLatch заставляет потоки ждать по методу wait() до тех пор, пока счет не достигнет нуля. Поэтому, возможно, вы хотите, чтобы все ваши потоки подождали до 3-х вызовов чего-то, тогда все потоки могут идти. Защелка вообще не может быть сброшена.

Семафор позволяет потокам получать разрешения, что предотвращает выполнение слишком большого количества потоков, блокируя, если он не может получить разрешения (ы), необходимые для продолжения. Разрешения могут быть возвращены в Семафор, чтобы другие ожидающие потоки продолжались.

+1

Семафор делает то, что делает семафор. его представленный прецедент действителен и, по-видимому, нет никакой разницы в нем countdownlatch против семафора, за исключением того, что он может повторно использовать семафор. Ожидание функционально такое же, как получение num_threads количества разрешений с .acquire (num_threads); Таким образом, единственное преимущество затвора обратного отсчета, по-видимому, заключается в том, что он имеет меньшую функциональность и был добавлен позже. преимущество в том, что вы не можете сбросить его, даже если хотите. ответы на копии папок с сайтов, которые являются сайтами copypaste, на самом деле не помогают, подробный анализ источников для обоих будет. – 2016-04-25 09:00:50

1

Рассматривая свободный источник, в реализации двух классов нет магии, поэтому их производительность должна быть одинаковой. Выберите тот, который делает ваше намерение более очевидным.

59

CountDownLatch используется, чтобы начать серию нитей, а затем ждать, пока все они не будут завершены (или пока они не называют countDown() заданное число раз.

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

В вашей Например, вы, по сути, используете Семафор в качестве своего рода графа UP Защелка.Учитывая, что ваше намерение состоит в том, чтобы ждать завершения всех потоков, использование CountdownLatch делает ваше намерение более ясным.

3

Допустим, вы вошли в гольф про магазин, в надежде найти четверку,

Когда вы стоите в очереди, чтобы получить тройник время одного из профессиональных магазинов обслуживающего персонала, по существу, вы назвали proshopVendorSemaphore.acquire() после того, как вы получите tee time, вы позвонили proshopVendorSemaphore.release(). Примечание: любой из бесплатных операторов может вам обслуживать, то есть общий ресурс.

Теперь вы подошли к стартеру, он запустил CountDownLatch(4) и позвонил await(), чтобы подождать других, для вашей стороны вы позвонили с подтверждением, то есть CountDownLatch. countDown(), а также остальная часть четверки. Когда все приходят, стартер дает идти вперед (возвращает await() звонок)

Теперь, после девяти отверстий, когда каждый из вас сделать перерыв, гипотетически позволяет включать стартер снова, он использует «новый» CountDownLatch(4) теэ от Hole 10, то же самое wait/sync as Hole 1. Однако, если стартер использовал CyclicBarrier, он мог бы сбросить один и тот же экземпляр в Отверстие 10 вместо второй защелки, в которой используется бросок &.

10

Краткое резюме:

  1. Semaphore и CountDownLatch служит другой цели.

  2. Семафор для управления доступом к ресурсам.

  3. Использование CountDownLatch ждать завершения всех потоков

Семафор определение из Javadocs:

Семафор поддерживает набор разрешений. Каждый приобретает() блокирует, если необходимо, до разрешения , а затем берет его. Каждый выпуск () добавляет разрешение, потенциально освобождающее блокирующего покупателя.

Однако, фактические объекты разрешения не используются; Семафор просто хранит количество доступных номеров и действует соответственно.

Как это работает?

семафоры используются для контроля количества одновременных потоков, использующих resource.That ресурс может быть что-то вроде общих данных, или блок кода (критический раздел) или любой другой файл.

Кол-во на Семафоре может идти вверх и вниз, поскольку разные темы звонят acquire() и release().Но в любой момент времени вы не можете увеличить число потоков больше, чем количество Семафор.

Семафор Прецеденты:

  1. Ограничения параллельного доступа к диску (это может убить производительность за счет конкурирующего диска ищет)
  2. создания Thread ограничения
  3. JDBC пула соединений/ограничение
  4. Сетевое подключение дросселирования
  5. Дросселирование CPU или задач с интенсивной памятью

Взгляните на это article на использование семафора.

CountDownLatch определение из Javadocs:

Слуховой синхронизации, которая позволяет одному или более потоков ждать, пока набор операций не выполняется в других потоках завершается.

Как это работает?

CountDownLatch работает, имея счетчик, инициализированный количеством потоков, который уменьшается каждый раз, когда поток завершает выполнение. Когда счетчик достигает нуля, это означает, что все потоки завершили выполнение, а ожидание потока на защелке возобновит выполнение.

CountDownLatch Прецеденты:

  1. Достижение максимального параллелизма: Иногда мы хотим, чтобы начать ряд нитей в то же время для достижения максимального параллелизма,
  2. Wait N потоков для завершения перед выполнением запуска
  3. Определение тупика.

Чтобы понять концепции CountDownLatch, ознакомьтесь с этим article.

Посмотрите на Fork Join Pool на этом article. Он имеет некоторое сходство с CountDownLatch.

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

  • Нет связанных вопросов^_^