Вопрос

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

java.util.параллельный.Обратный отсчет

вместо того , чтобы

java.util.concurrent.Семафор?

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

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:Обратный отсчет времени

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

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

Это было полезно?

Решение

Защелка обратного отсчета часто используется для полной противоположности вашему примеру.Как правило, у вас было бы много потоков, блокирующих "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();
}

Тем не менее, защелку обратного отсчета можно безопасно использовать так, как вы показали в своем примере.

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

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

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

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

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

  1. Семафор и Обратный отсчет времени служит другой цели.

  2. Использование Семафор чтобы контролировать доступ потока к ресурсу.

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

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

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

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

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

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

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

Варианты использования семафора:

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

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

Обратный отсчет времени определение из javadocs:

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

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

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

Варианты использования CountDownLatch:

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

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

Взгляните на Вилка Присоединяется К Пулу при этом Статья слишком.Это имеет некоторое сходство с Обратный отсчет времени.

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top