Поскольку нет ответа, помеченного как принятый, я попытался создать пример блокировки в реальном времени;
Оригинальная программа была написана мной в апреле 2012 года для изучения различных концепций многопоточности. На этот раз я изменил его, чтобы создать тупик, состояние гонки, livelock и т. Д.
Итак, давайте сначала разберемся с постановкой задачи;
Проблема создателя печенья
Существует несколько контейнеров с ингредиентами: ChocoPowederContainer , WheatPowderContainer . CookieMaker берет некоторое количество порошка из контейнеров с ингредиентами для выпечки Cookie . Если производитель печенья находит контейнер пустым, он проверяет другой контейнер, чтобы сэкономить время. И ждет, пока Filler не заполнит требуемый контейнер. Существует Filler , который регулярно проверяет контейнер и заполняет некоторое количество, если это необходимо контейнеру.
Пожалуйста, проверьте полный код на github ;
Позвольте мне кратко объяснить вам реализацию.
- Я запускаю Наполнитель как поток демона. Так что он будет наполнять контейнеры на регулярной основе. Чтобы сначала наполнить контейнер, он запирает контейнер -> проверяет, нужен ли ему порошок -> заполняет его -> сигнализирует всем производителям, которые его ждут -> разблокировать контейнер.
- Я создаю CookieMaker и устанавливаю, что он может одновременно выпекать до 8 файлов cookie. И я начинаю 8 потоков, чтобы испечь печенье.
- Каждая производственная нить создает 2 вызываемые вспомогательные нити для извлечения порошка из контейнеров.
- дополнительная нить захватывает контейнер и проверяет, достаточно ли порошка. Если нет, подождите некоторое время. Как только наполнитель заполнит контейнер, он заберет порошок и разблокирует контейнер.
- Теперь он выполняет другие действия, такие как: приготовление смеси, выпечка и т. Д.
Давайте посмотрим на код:
CookieMaker.java
private Integer getMaterial(final Ingredient ingredient) throws Exception{
:
container.lock();
while (!container.getIngredient(quantity)) {
container.empty.await(1000, TimeUnit.MILLISECONDS);
//Thread.sleep(500); //For deadlock
}
container.unlock();
:
}
IngredientContainer.java
public boolean getIngredient(int n) throws Exception {
:
lock();
if (quantityHeld >= n) {
TimeUnit.SECONDS.sleep(2);
quantityHeld -= n;
unlock();
return true;
}
unlock();
return false;
}
Все работает нормально, пока Наполнитель не заполнит контейнеры. Но если я забываю запустить наполнитель или наполнитель неожиданно уходит, дочерние потоки продолжают изменять свои состояния, чтобы позволить другому производителю пойти и проверить контейнер.
Я также создал демон ThreadTracer , который следит за состоянием потоков и взаимными блокировками. Это вывод из консоли;
2016-09-12 21:31:45.065 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:RUNNABLE, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
2016-09-12 21:31:45.065 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
WheatPowder Container has 0 only.
2016-09-12 21:31:45.082 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:RUNNABLE]
2016-09-12 21:31:45.082 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
Вы заметите, что вложенные потоки меняют свои состояния и ждут.