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 защелка не может быть использована повторно и, что более важно, вам нужно заранее знать, сколько потоков будет создано (или подождать, пока все они будут запущены, прежде чем создавать защелку).

Так в какой ситуации защелка может быть предпочтительнее?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
97
0
54 182
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

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

Ответ принят как подходящий

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

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();
}

При этом CountDownLatch можно безопасно использовать так, как вы показали в своем примере.

Спасибо. Итак, два моих примера не были бы эквивалентными, если бы несколько потоков могли ждать защелки ... если только sem.acquire (num_threads); за ним следует sem.release (num_threads) ;? Я думаю, это снова сделало бы их эквивалентными.

finnw 09.10.2008 01:27

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

James Schek 09.10.2008 01:38

Документация Java, кажется, подразумевает, что CountdownLatch хорошо сочетается с его примером: docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/…‌. В частности, «CountDownLatch, инициализированный значением N, может использоваться, чтобы заставить один поток ждать, пока N потоков не завершат какое-либо действие или какое-то действие не будет выполнено N раз».

Chris Morris 21.02.2013 22:48

Ты прав. Я немного обновлю свой ответ, чтобы отразить, что это наиболее частые случаи использования CountDownLatch, которые я видел, по сравнению с предполагаемым использованием.

James Schek 21.02.2013 23:50

Это отвечает на вопрос Какая функция CountDownLatch используется чаще всего? Это не отвечает на исходный вопрос о преимуществах / различиях использования CountDownLatch по сравнению с семафором.

Marco Lackovic 24.04.2013 20:45

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

Lassi Kinnunen 25.04.2016 12:07

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

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

В вашем примере вы по сути используете Semaphore как своего рода CountВВЕРХLatch. Учитывая, что вы намереваетесь дождаться завершения всех потоков, использование CountdownLatch проясняет ваше намерение.

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

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

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

Теперь, после девяти лунок, когда каждый из вас делает перерыв, гипотетически позволяет снова задействовать стартера, он использует «новый» CountDownLatch(4) для выхода из лунки 10, такое же ожидание / синхронизация, как и в лунке 1.

Однако, если бы стартер использовал CyclicBarrier для начала, он мог бы сбросить тот же экземпляр в лунке 10 вместо второй защелки, которая использует & throw.

Я не уверен, что понимаю ваш ответ, но если вы пытаетесь описать, как работают CountdownLatch и Semaphore, это не является предметом вопроса.

finnw 02.08.2013 03:37

К сожалению, я ничего не знаю о гольфе.

ring bearer 26.05.2015 09:13

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

Lassi Kinnunen 25.04.2016 12:06

Краткое содержание:

  1. Semaphore и CountDownLatch служат разным целям.

  2. Используйте Semaphore для управления доступом потока к ресурсу.

  3. Используйте CountDownLatch, чтобы дождаться завершения всех потоков

Определение Semaphore из Javadocs:

A Semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer.

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

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

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

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

Semaphore Примеры использования:

  1. Ограничение одновременного доступа к диску (это может снизить производительность из-за конкурирующий диск ищет)
  2. Ограничение создания потока
  3. Пул / ограничение соединений JDBC
  4. Регулирование сетевого подключения
  5. Регулирование задач, интенсивно использующих ЦП или память

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

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

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

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

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

CountDownLatch Примеры использования:

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

Взгляните на этот статья, чтобы четко понять концепции CountDownLatch.

Взгляните на Форк присоединиться к пулу и на этот статья. Он имеет некоторое сходство с CountDownLatch.

Другие вопросы по теме