Семантически, они разные; и это важно, потому что это упрощает чтение кода. Когда я вижу Семафор, я сразу начинаю думать о «ограниченном количестве общего ресурса». Когда я вижу CountDownLatch, я сразу начинаю думать «куча потоков, ожидающих« go! ». Сигнал «. Если вы дадите мне первое в коде, которое действительно нуждается в последнем, это сбивает с толку.
В этом смысле Семафор, используемый как CountDownLatch, немного похож на garden-path sentence; в то время как технически правильно, это заводит людей в заблуждение и смущает их.
С точки зрения более прагматичного использования CountDownLatch просто проще, если это все, что вам нужно. Проще лучше!
Что касается повторного использования CountDownLatch, это усложнит его использование. Например, предположим, вы пытаетесь поставить в очередь потоки A, B и C для некоторой работы. У вас их ждут на защелке, а затем вы отпустите его. Затем вы сбросите его, предположительно, для очереди на темы D, E и F для какой-либо другой работы. Но что произойдет, если (из-за состояния гонки), нить B на самом деле еще не освобождена от первой защелки? Что, если он еще не добрался до звонка await()
? Закрываете ли вы ворота и говорите, чтобы ждать с D, E и F для второго открытия? Это может даже вызвать тупик, если второе открытие зависит от работы, которую должен выполнять B!
У меня были те же вопросы, которые вы задали при перезагрузке, когда я впервые прочитал о CountDownLatch. Но на практике я редко даже хотел сбросить его; каждая единица «wait then go» (A-B-C, а затем D-E-F), естественно, поддается созданию собственного CountDownLatch, чтобы идти вместе с ним, и все остается красивым и простым.
Даже если учесть этот вопрос как дубликат, но из-за второго запроса, я этого не делал> Почему он был предназначен для использования только один раз? Я думаю, что легко добавить метод set для сброса счетчика. –