print(this + " " + "выход через прерывание"),
public String toStringO { return "Философ " + id; } } /// ~
В методе Philosopher.run() все философы непрерывно переходят от размышлений к еде, и наоборот. Метод pause() делает паузу случайной продолжительности, если значение ponderFactor отлично от нуля. Итак, Philosopher думает в течение случайного промежутка времени, затем пытается захватить левую и правую палочки вызовами take(), ест в течение случайного промежутка времени, а затем все повторяется.
В следующей версии программы возникает взаимная блокировка:
// concurrency/DeadlockingDiningPhi1osophers.java // Демонстрация скрытой возможности взаимной блокировки II {Args 0 5 timeout} import java util concurrent *.
public class DeadlockingDiningPhi1osophers {
public static void main(String[] args) throws Exception { int ponder = 5, if(args length > 0)
ponder = Integer.parselnt(args[0]); int size = 5; if(args length > 1)
size = Integer parselnt(args[l]); ExecutorService exec = Executors newCachedThreadPoolО; Chopstick[] sticks = new Chopstick[size]; for(int i = 0; i < size; i++)
sticksCi] = new ChopstickO; for(int 1=0. i < size, i++)
exec execute(new PhiTosopherC
sticks[i], sticks[(i+l) % size], i, ponder)); if(args length == 3 && args[2].equals("timeout")) TimeUnit.SECONDS sleep(5);
\ else {
System.out.рппШСНажмите 'Enter', чтобы завершить работу"); System in readO;
}
exec shutdownNow();
}
} ///:-
Если философы почти не тратят время на размышления, они будут постоянно конкурировать за палочки при попытках поесть, и взаимные блокировки возникают гораздо чаще.
Первый аргумент командной строки изменяет значение ponder, влияющее на продолжительность размышлений. Если философов очень много или они проводят большую часть времени в размышлениях, взаимная блокировка может и не возникнуть, хотя ее теоретическая вероятность отлична от нуля. С нулевым аргументом взаимная блокировка наступает намного быстрее.
Объектам Chopstick не нужны внутренние идентификаторы; они идентифицируются по своей позиции в массиве sticks. Каждому конструктору Philosopher передаются ссылки на правую и левую палочки Chopstick. Последнему Philosopher в качестве правой палочки передается нулевой объект Chopstick; круг замыкается. Теперь может возникнуть ситуация, когда все философы одновременно попытаются есть, и каждый из них будет ожидать, пока сосед положит свою палочку. В программе наступает взаимная блокировка.
Если философы тратят на размышления больше времени, чем на еду, вероятность взаимной блокировки значительно снижается. Даже может возникнуть иллюзия, что программа свободна от блокировок (при ненулевом значении ponder или большом количестве объектов Philosopher), хотя на самом деле это не так. Именно этим и интересен настоящий пример: программа вроде бы ведет себя верно, тогда как на самом деле возможна взаимная блокировка.
Для решения проблемы необходимо осознавать, что тупик имеет место при стечении следующих четырех обстоятельств:
1. Взаимное исключение: по крайней мере один ресурс, используемый потоками, не должен быть совместно используемым. В нашем случае одной палочкой для еды не могут одновременно есть два философа.