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

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

Жанры

Программирование на Java

Вязовик Н.А.

Шрифт:

Также допустимы методы static synchronized. При их вызове блокировка устанавливается на объект класса Class, отвечающего за тип, у которого вызывается этот метод.

При работе с блокировками всегда надо помнить о возможности появления deadlock – взаимных блокировок, которые приводят к зависанию программы. Если один поток заблокировал один ресурс и пытается заблокировать второй, а другой поток заблокировал второй и пытается заблокировать первый, то такие потоки уже никогда не выйдут из состояния ожидания.

Рассмотрим простейший пример:

public class DeadlockDemo {

//

Два объекта-ресурса

public final static Object one=new Object, two=new Object;

public static void main(String s[]) {

// Создаем два потока, которые будут

// конкурировать за доступ к объектам

// one и two

Thread t1 = new Thread {

public void run {

// Блокировка первого объекта

synchronized(one) {

Thread.yield;

// Блокировка второго объекта

synchronized (two) {

System.out.println("Success!");

}

}

}

};

Thread t2 = new Thread {

public void run {

// Блокировка второго объекта

synchronized(two) {

Thread.yield;

// Блокировка первого объекта

synchronized (one) {

System.out.println("Success!");

}

}

}

};

// Запускаем потоки t1.start;

t2.start;

}

}

Пример 12.4.

Если запустить такую программу, то она никогда не закончит свою работу. Обратите внимание на вызовы метода yield в каждом потоке. Они гарантируют, что когда один поток выполнил первую блокировку и переходит к следующей, второй поток находится в таком же состоянии. Очевидно, что в результате оба потока "замрут", не смогут продолжить свое выполнение. Первый поток будет ждать освобождения второго объекта, и наоборот. Именно такая ситуация называется "мертвой блокировкой", или deadlock. Если один из потоков успел бы заблокировать оба объекта, то программа успешно бы выполнилась до конца. Однако многопоточная архитектура не дает никаких гарантий, как именно потоки будут выполняться друг относительно друга. Задержки (которые в примере моделируются вызовами yield ) могут возникать из логики программы (необходимость произвести вычисления), действий пользователя (не сразу нажал кнопку "ОК"), занятости ОС (из-за нехватки физической оперативной памяти пришлось воспользоваться виртуальной), значений приоритетов потоков и так далее.

В Java нет никаких средств распознавания или предотвращения ситуаций deadlock. Также нет способа перед вызовом синхронизированного метода узнать, заблокирован ли уже объект другим потоком. Программист сам должен строить работу программы таким образом, чтобы неразрешимые блокировки не возникали. Например, в рассмотренном примере достаточно было организовать блокировки объектов в одном порядке (всегда сначала первый, затем второй) – и программа всегда выполнялась бы успешно.

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

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

Методы wait, notify, notifyAll класса Object

Наконец, перейдем к рассмотрению трех методов класса Object, завершая описание механизмов поддержки многопоточности в Java.

Каждый объект в Java имеет не только блокировку для synchronized блоков и методов, но и так называемый wait-set, набор потоков исполнения. Любой поток может вызвать метод wait любого объекта и таким образом попасть в его wait-set. При этом выполнение такого потока приостанавливается до тех пор, пока другой поток не вызовет у этого же объекта метод notifyAll, который пробуждает все потоки из wait-set. Метод notify пробуждает один случайно выбранный поток из данного набора.

Однако применение этих методов связано с одним важным ограничением. Любой из них может быть вызван потоком у объекта только после установления блокировки на этот объект. То есть либо внутри synchronized -блока с ссылкой на этот объект в качестве аргумента, либо обращения к методам должны быть в синхронизированных методах класса самого объекта. Рассмотрим пример:

public class WaitThread implements Runnable {

private Object shared;

public WaitThread(Object o) {

shared=o;

}

public void run {

synchronized (shared) {

try {

shared.wait;

}

catch (InterruptedException e) {

}

System.out.println("after wait");

}

}

public static void main(String s[]) {

Object o = new Object;

WaitThread w = new WaitThread(o);

new Thread(w).start;

try {

Thread.sleep(100);

}

catch (InterruptedException e) {

}

System.out.println("before notify");

synchronized (o) {

o.notifyAll;

}

}

}

Результатом программы будет:

before notify

after wait

Обратите внимание, что метод wait, как и sleep, требует обработки InterruptedException, то есть его выполнение также можно прервать методом interrupt.

В заключение рассмотрим более сложный пример для трех потоков:

public class ThreadTest implements Runnable {

final static private Object shared=new Object;

private int type;

public ThreadTest(int i) {

type=i;

}

public void run {

if (type==1 || type==2) {

synchronized (shared) {

try {

shared.wait;

}

catch (InterruptedException e) {

}

System.out.println("Thread "+type+" after wait");

}

}

else {

synchronized (shared) {

shared.notifyAll;

System.out.println("Thread "+type+" after notifyAll");

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

Тринадцатый II

NikL
2. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый II

Как я строил магическую империю 4

Зубов Константин
4. Как я строил магическую империю
Фантастика:
боевая фантастика
постапокалипсис
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 4

На обочине 40 плюс. Кляча не для принца

Трофимова Любовь
Проза:
современная проза
5.00
рейтинг книги
На обочине 40 плюс. Кляча не для принца

Черный дембель. Часть 2

Федин Андрей Анатольевич
2. Черный дембель
Фантастика:
попаданцы
альтернативная история
4.25
рейтинг книги
Черный дембель. Часть 2

Воин

Бубела Олег Николаевич
2. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.25
рейтинг книги
Воин

Я Гордый часть 5

Машуков Тимур
5. Стальные яйца
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Я Гордый часть 5

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21

Последний реанорец. Том I и Том II

Павлов Вел
1. Высшая Речь
Фантастика:
фэнтези
7.62
рейтинг книги
Последний реанорец. Том I и Том II

Воронцов. Перезагрузка

Тарасов Ник
1. Воронцов. Перезагрузка
Фантастика:
попаданцы
альтернативная история
фантастика: прочее
5.00
рейтинг книги
Воронцов. Перезагрузка

Бастард Императора. Том 15

Орлов Андрей Юрьевич
15. Бастард Императора
Фантастика:
городское фэнтези
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Бастард Императора. Том 15

Спасите меня, Кацураги-сан! Том 4

Аржанов Алексей
4. Токийский лекарь
Фантастика:
городское фэнтези
попаданцы
дорама
фэнтези
5.00
рейтинг книги
Спасите меня, Кацураги-сан! Том 4

Хозяин Стужи 3

Петров Максим Николаевич
3. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
7.00
рейтинг книги
Хозяин Стужи 3

Жена неверного генерала, или Попаданка на отборе

Удалова Юлия
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Жена неверного генерала, или Попаданка на отборе