Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

java.io.InterruptedlOException Receiver read exception *///:-

Классы Sender и Receiver представляют задачи, которые должны взаимодействовать друг с другом. В классе Sender создается канал PipedWriter, существующий как автономный объект, однако при создании канала PipedReader в классе Receiver конструктору необходимо передать ссылку на PipedWriter. Sender записывает данные в канал Writer и бездействует в течение случайно выбранного промежутка времени. Класс Receiver не содержит вызовов sleep или wait, но при проведении чтения методом read он автоматически блокируется при отсутствии данных.

Заметьте, что потоки sender и receiver запускаются из main после того, как объекты были полностью сконструированы. Если запускать не полностью сконструированные объекты, каналы на различных платформах могут демонстрировать несогласованное поведение.

Взаимная блокировка

Итак, потоки способны перейти в блокированное состояние, а объекты могут обладать синхронизированными методами, которые запрещают использование объекта до тех пор, пока не будет снята блокировка. Возможна ситуация, в которой один поток ожидает другой поток, тот, в свою очередь, ждет освобождения еще одного потока и т. д., пока эта цепочка не замыкается на поток, который ожидает освобождения первого потока. Получается замкнутый круг потоков, которые дожидаются освобождения друг друга, и никто не может двинуться первым. Такая ситуация называется взаимной блокировкой (deadlock) (или «клинчем». — Примеч. ред.).

Если вы запускаете программу и в ней незамедлительно возникает взаимная блокировка, проблему удается немедленно отследить. По-настоящему неприятна ситуация, когда ваша программа по всем признакам работает прекрасно, но тем не менее в какой-то момент входит во взаимную блокировку. Такая опасность незаметно присутствует в программе, пока нежданно-негаданно не проявится у заказчика (и, скорее всего, легко воспроизвести эту ситуацию вам не удастся). Таким образом, тщательное проектирование программы с целью предотвращения взаимных блокировок — важнейшая часть разработки параллельных программ.

Классический пример взаимной блокировки, предложенный Эдгаром Дейк-строй — задача об обедающих философах. В стандартной формулировке говорится о пяти философах, но, как будет показано далее, допустимо любое количество. Часть времени философы проводят размышляя, часть времени проводят за едой. Когда они размышляют, то не нуждаются в общих ресурсах, но во время обеда они сидят за круглым столом с ограниченным количеством столовых приборов. В описании оригинальной задачи философы пользуются вилками, и, чтобы набрать спагетти из миски в центре стола, им требуются две вилки. Наверное, задача будет выглядеть более логично, если заменить вилки палочками для еды — очевидно, что каждому философу понадобятся две палочки.

Философы, как это часто бывает, очень бедны, и они смогли позволить себе приобрести лишь пять палочек (или в более общем виде — количество палочек совпадает с количеством философов). Последние разложены кругом по столу, между философами. Когда философу захочется поесть, ему придется взять палочку слева и справа. Если с какой-либо стороны желаемая палочка уже в руке другого философа, только что оторвавшемуся от размышлений придется подождать ее освобождения:

//: concurrency/Chopstick.java

// Палочки для обедающих философов.

public class Chopstick {

private boolean taken = false;

public synchronized

void takeO throws InterruptedException { while(taken)

waitO; taken = true;

}

public synchronized void dropO { taken = false; notifyAllО;

}

Два философа (Philosopher) ни при каких условиях не смогут успешно взять (takeQ) одну и ту же палочку (Chopstick) одновременно. Если один философ уже взял палочку, другому философу придется подождать (wait), пока она не будет освобождена текущим пользователем (drop).

Когда задача Philosopher вызывает take, она ожидает, пока флаг taken не перейдет в состояние false (то есть пока палочка не будет освобождена тем философом, который держит ее в данный момент). Далее задача устанавливает флаг taken равным true, показывая тем самым, что палочка занята. Завершив работу с Chopstick, Philosopher вызывает drop, чтобы изменить флаг и оповестить (notifyAll) всех остальных философов, ожидающих освобождения палочки:

// concurrency/Philosopher java // Обедающий философ import java.util concurrent *. import java util *,

import static net mindview util Print *;

public class Philosopher implements Runnable { private Chopstick left, private Chopstick right, private final int id, private final int ponderFactor; private Random rand = new Random(47). private void pauseO throws InterruptedException { if(ponderFactor == 0) return. TimeUnit MILLISECONDS sleep(

rand.nextInt(ponderFactor * 250));

}

public Philosopher(Chopstick left. Chopstick right, int ident, int ponder) { this.left = left; this right = right; id = ident,

ponderFactor = ponder;

}

public void run { try {

while(IThread interruptedO) {

print(this + " " + "думает"), pauseO,

// Философ проголодался

print(this + " " + "берет правую").

right takeO.

print(this + " " + "берет левую"); left. takeO.

print(this + " " + "ест"); pauseO; right dropO; left.dropO.

}

} catchdnterruptedException e) {

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 *.

Поделиться:
Популярные книги

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Отмороженный

Гарцевич Евгений Александрович
1. Отмороженный
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Отмороженный

#Бояръ-Аниме. Газлайтер. Том 37

Володин Григорий Григорьевич
37. История Телепата
Фантастика:
фэнтези
аниме
боевая фантастика
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 37

Адвокат империи

Карелин Сергей Витальевич
1. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
фэнтези
5.75
рейтинг книги
Адвокат империи

Двойник короля 11

Скабер Артемий
11. Двойник Короля
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Двойник короля 11

Законы Рода. Том 8

Андрей Мельник
8. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 8

Вернувшийся: Первые шаги. Том II

Vector
2. Вернувшийся
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Вернувшийся: Первые шаги. Том II

Эволюционер из трущоб. Том 7

Панарин Антон
7. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 7

На границе империй. Том 10. Часть 5

INDIGO
23. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 5

Бандит

Щепетнов Евгений Владимирович
1. Петр Синельников
Фантастика:
фэнтези
7.92
рейтинг книги
Бандит

Неудержимый. Книга XXX

Боярский Андрей
30. Неудержимый
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXX

Законы Рода. Том 4

Андрей Мельник
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Золушка вне правил

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.83
рейтинг книги
Золушка вне правил

Зайти и выйти

Суконкин Алексей
Проза:
военная проза
5.00
рейтинг книги
Зайти и выйти