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

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

Жанры

Философия Java3

Эккель Брюс

Шрифт:

Предотвратить такое столкновение интересов несложно — надо блокировать ресурс для других потоков, пока он находится в ведении одного потока. Первый поток, получивший доступ к ресурсу, вешает на него «замок», и тогда все остальные потоки не смогут получить этот ресурс до тех пор, пока «замок» не будет снят, и только после этого другой поток овладеет ресурсом и заблокирует его, и т. д. Если переднее сиденье машины является для детей ограниченным ресурсом, то ребенок, первым крикнувший «Чур, я спереди!», отстоял свое право на «блокировку».

Для решения проблемы соперничества потоков фактически все многопоточные схемы синхронизируют доступ к разделяемым ресурсам.

Это означает, что доступ к разделяемому ресурсу в один момент времени может получить только один поток. Чаще всего это выполняется помещением фрагмента кода в секцию блокировки так, что одновременно пройти по этому фрагменту кода может только один поток. Поскольку такое предложение блокировки дает эффект взаимного исключения, этот механизм часто называют мьютексом (MUTual Exclusion).

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

Аналогия немного нарушается, когда дверь в ванную комнату снова открывается, и приходит время передать доступ другому потоку. Как люди на самом деле не становятся в очередь, так и здесь мы точно не знаем, кто «зайдет в ванную» следующим, потому что поведение планировщика потоков недетермини-ровано. Существует гипотетическая группа блокированных потоков, толкущихся у двери, и, когда поток, который занимал «ванную», разблокирует ее и уйдет, тот поток, что окажется ближе всех к двери, «войдет» в нее. Как уже было замечено, планировщику можно давать подсказки методами yield и setPriority, но эти подсказки необязательно будут иметь эффект, в зависимости от вашей платформы и реализации виртуальной машины JVM.

В Java есть встроенная поддержка для предотвращения конфликтов в виде ключевого слова synchronized. Когда поток желает выполнить фрагмент кода, охраняемый словом synchronized, он проверяет, доступен ли семафор, получает доступ к семафору, выполняет код и освобождает семафор.

Разделяемый ресурс чаще всего является блоком памяти, представляющим объект, но это также может быть файл, порт ввода/вывода или устройство (скажем, принтер). Для управления доступом к разделяемому ресурсу вы сначала помещаете его внутрь объекта. После этого любой метод, получающий доступ к ресурсу, может быть объявлен как synchronized. Это означает, что, если задача выполняется внутри одного из объявленных как synchronized методов, все остальные потоки не сумеют зайти ни в какой synchronized-метод до тех пор, пока первый поток не вернется из своего вызова.

Как известно, в окончательной версии кода поля класса обычно объявляются закрытыми (private), а доступ к их памяти осуществляется только посредством методов. Чтобы предотвратить конфликты, объявите такие методы синхронизированными (с помощью ключевого слова synchronized):

synchronized void f { /* .. */ }

synchronized void g{ /*.. */ }

Каждый объект содержит объект простой блокировки (также называемый монитором). При вызове любого синхронизированного (synchronized) метода объект переходит в состояние блокировки, и пока этот метод не закончит свою работу и не снимет блокировку, другие синхронизированные методы для объекта не могут быть вызваны. В только что рассмотренном примере, если для объекта вызывается метод f, метод д не будет вызван до тех пор, пока метод f не

завершит свою работу и не сбросит блокировку. Таким образом, монитор совместно используется всеми синхронизированными методами определенного объекта и предотвращает использование общей памяти несколькими потоками одновременно.

Один поток может блокировать объект многократно. Это происходит, когда метод вызывает другой метод того же объекта, который, в свою очередь, вызывает еще один метод того же объекта, и т. д. Виртуальная машина JVM следит за тем, сколько раз объект был заблокирован. Если объект не блокировался, его счетчик равен нулю. Когда задача захватывает объект в первый раз, счетчик увеличивается до единицы. Каждый раз, когда задача снова овладевает объектом блокировки того же объекта, счетчик увеличивается. Естественно, что все это разрешается только той задаче, которая инициировала первичную блокировку. При выходе задачи из синхронизированного метода счетчик уменьшается на единицу до тех пор, пока не делается равным нулю, после чего объект блокировки данного объекта становится доступен другим потокам.

Также существует отдельный монитор для класса (часть объекта Class), который следит за тем, чтобы статические (static) синхронизированные (synchronized). методы не использовали одновременно общие статические данные класса.

Синхронизация для примера EvenGenerator

Включив в программу EvenGenerator.java поддержку synchronized, мы можем предотвратить нежелательный доступ со стороны потоков:

//• concurrency/SynchronizedEvenGenerator java

// Упрощение работы с мьютексами с использованием

// ключевого слова synchronized

// {RunByHand}

public class

SynchronizedEvenGenerator extends IntGenerator { private int currentEvenValue = 0; public synchronized int nextO { ++currentEvenValue, Thread yieldO, // Ускоряем сбой ++currentEvenValue. return currentEvenValue.

}

public static void main(String[] args) {

EvenChecker test (new SynchronizedEvenGeneratorO);

}

} III ~

Вызов Thread.yield между двумя инкрементами повышает вероятность переключения контекста при нахождении currentEvenValue в нечетном состоянии. Так как мьютекс позволяет выполнять критическую секцию не более чем одной задаче, сбоев не будет.

Первая задача, входящая в next, устанавливает блокировку, а все остальные задачи, пытающиеся ее установить, блокируются до момента снятия блокировки первой задачей. В этой точке механизм планирования выбирает другую задачу, ожидающую блокировки. Таким образом, в любой момент времени только одна задача может проходить по коду, защищенному мьютексом.

Объекты Lock

Библиотека Java SE5 java.utiLconcurrent также содержит явный механизм управления мьютексами, определенный в java.util.concurrent.locks. Объект Lock можно явно создать в программе, установить или снять блокировку; правда, полученный код будет менее элегантным, чем при использовании встроенной формы. С другой стороны, он обладает большей гибкостью при решении некоторых типов задач. Вот как выглядит пример SynchronizedEvenGenerator.java с явным использованием объектов Lock:

II: concurrency/MutexEvenGenerator.java

// Предотвращение потоковых конфликтов с использованием мьютексов.

II {RunByHand}

import java.util.concurrent.locks.*;

public class MutexEvenGenerator extends IntGenerator { private int currentEvenValue = 0, private Lock lock = new ReentrantLockO; public int nextO { lock lockO; try {

++currentEvenValue; Thread.yieldO; // Ускоряем сбой ++currentEvenValue; return currentEvenValue; } finally { продолжение ^

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

Жена проклятого некроманта

Рахманова Диана
Фантастика:
фэнтези
6.60
рейтинг книги
Жена проклятого некроманта

Сын Тишайшего

Яманов Александр
1. Царь Федя
Фантастика:
попаданцы
альтернативная история
фэнтези
5.20
рейтинг книги
Сын Тишайшего

Демон

Парсиев Дмитрий
2. История одного эволюционера
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Демон

30 сребреников

Распопов Дмитрий Викторович
1. 30 сребреников
Фантастика:
попаданцы
альтернативная история
фэнтези
фантастика: прочее
5.00
рейтинг книги
30 сребреников

Небо в огне. Штурмовик из будущего

Политов Дмитрий Валерьевич
Военно-историческая фантастика
Фантастика:
боевая фантастика
7.42
рейтинг книги
Небо в огне. Штурмовик из будущего

Осознание. Пятый пояс

Игнатов Михаил Павлович
14. Путь
Фантастика:
героическая фантастика
5.00
рейтинг книги
Осознание. Пятый пояс

Камень

Минин Станислав
1. Камень
Фантастика:
боевая фантастика
6.80
рейтинг книги
Камень

Блокада. Знаменитый роман-эпопея в одном томе

Чаковский Александр Борисович
Проза:
военная проза
7.00
рейтинг книги
Блокада. Знаменитый роман-эпопея в одном томе

Цикл "Отмороженный". Компиляция. Книги 1-14

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

Книга 4. Игра Кота

Прокофьев Роман Юрьевич
4. ОДИН ИЗ СЕМИ
Фантастика:
фэнтези
боевая фантастика
рпг
6.68
рейтинг книги
Книга 4. Игра Кота

Мастер 2

Чащин Валерий
2. Мастер
Фантастика:
фэнтези
городское фэнтези
попаданцы
технофэнтези
4.50
рейтинг книги
Мастер 2

Новый Рал 2

Северный Лис
2. Рал!
Фантастика:
фэнтези
7.62
рейтинг книги
Новый Рал 2

Низший 2

Михайлов Дем Алексеевич
2. Низший!
Фантастика:
боевая фантастика
7.07
рейтинг книги
Низший 2

Под маской, или Страшилка в академии магии

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.78
рейтинг книги
Под маской, или Страшилка в академии магии