Синхронизация по ресурсам и событиям
Использование потоков выполнения порождает целый ряд проблем не только в плане отладки программ, но и при организации взаимодействия между разными потоками.
Синхронизация по ресурсам
Если разные потоки получают доступ к одним и тем же данным, причём один из них или они оба меняют эти данные, для них требуется обеспечить установить разграничение доступа. Пока один поток меняет данные, второй не должен иметь права их читать или менять. Он должен дожидаться окончания доступа к данным первого потока. Говорят, что осуществляется синхронизация потоков. В Java для этих целей служит оператор synchronize (“синхронизировать”). Такой тип синхронизации называется синхронизацией по ресурсам и обеспечивает блокировку данных на то время, которое необходимо потоку для выполнения тех или иных действий. В Java такого рода блокировка осуществляется на основе концепции мониторов и в применении к Java заключается в следующем. Под монитором понимается некая управляющая конструкция, обеспечивающая монопольный доступ к объекту. Если во время выполнения синхронизованного метода объекта другой поток попробует обратиться к методам или данным этого объекта, он будет блокирован до тех пор, пока не закончится выполнение синхронизованного метода. При запуске синхронизованного метода говорят, что объект входит в монитор, при завершении – что объект выходит из монитора. При этом поток, внутри которого вызван синхронизованный метод, считается владельцем данного монитора.
Имеется два способа синхронизации по ресурсам: синхронизация объекта и синхронизация метода.
Синхронизация объекта obj1 (его иногда называют объектом действия) осуществляется следующим образом:
synchronized(obj1) оператор;
Например:
synchronized(obj1){
...
m1(obj1);
...
obj1.m2();
...
}
В данном случае в качестве синхронизованного оператора выступает участок кода в фигурных скобках. Во время выполнения этого участка доступ к объекту obj1 блокируется для всех других потоков. Это означает, что пока будет выполняться вызов оператора, выполнение вызова любого синхронизованного метода или синхронизованного оператора для этого объекта будет приостановлено до окончания работы оператора.
Данный способ синхронизации обычно используется для экземпляров классов, разработанных без расчёта на работу в режиме многопоточности.
Второй способ синхронизации по ресурсам используется при разработке класса, рассчитанного на взаимодействия в многопоточной среде. При этом методы, критичные к атомарности операций с данными (обычно - требующие согласованное изменение нескольких полей данных), объявляются как синхронизованные с помощью модификатора synchronized:
public class ИмяКласса{
...
public synchronized тип метод(...){
...
}
}
Вызов данного метода из объекта приведёт к вхождению данного объекта в монитор.
Пример:
public class C1{
public synchronized void m1(){
}
}
C1 obj1=new C1();
obj1.m1();
Пока будет выполняться вызов obj1.m1(), доступ из других потоков к объекту obj1 будет блокирован – выполнение вызова любого синхронизованного метода или синхронизованного оператора для этого объекта будет приостановлено до окончания работы метода m1().
Если синхронизованный метод является не методом объекта, а методом класса, при вызове метода в монитор входит класс, и приостановка до окончания работы метода будет относиться ко всем вызовам синхронизованных методов данного класса.
Итак, возможна синхронизация как целого метода (но только при задании его реализации в классе), так и отдельных операторов. Иногда синхронизованную область кода (метод или оператор) называют критической секцией кода.
Синхронизация по событиям
Кроме синхронизации по данным имеется синхронизация по событиям, когда параллельно выполняющиеся потоки приостанавливаются вплоть до наступления некоторого события, о котором им сигнализирует другой поток. Основными операциями при таком типе синхронизации являются wait (“ждать”) и notify (“оповестить”).
В Java синхронизацию по событиям обеспечивают следующие методы, заданные в классе Object и наследуемые всеми остальными классами:
void wait() – поток, внутри которого какой-либо объект вызвал данный метод (владелец монитора), переводится в состояние ожидания. Поток приостанавливает работу своего метода run() вплоть до поступления объекту, вызвавшему приостановку (“засыпание”) потока уведомления notify() или notifyAll(). При неправильной попытке “разбудить” поток соответствующий код компилируется, но при запуске вызывает появление исключения llegalMonitorStateException.
void wait(long millis) – то же, но ожидание длится не более millis миллисекунд.
void wait(long millis, int nanos) – то же, но ожидание длится не более millis миллисекунд и nanos наносекунд.
void notify() – оповещение, приводящее к возобновлению работы потока, ожидающего выхода данного объекта из монитора. Если таких потоков несколько, выбирается один из них. Какой – зависит от реализации системы.
void notifyAll() - оповещение, приводящее к возобновлению работы всех потоков, ожидающих выхода данного объекта из монитора.
Метод wait для любого объекта obj следует использовать следующим образом - необходимо организовать цикл while, в котором следует выполнять оператор wait:
synchronized(obj){
while(not условие)
obj.wait();
…//выполнение операторов после того, как условие стало true
}
При этом не следует беспокоиться, что цикл while постоянно крутится и занимает много ресурсов процессора. Этого не происходит: после вызова obj.wait() поток, в котором находится указанный код, “засыпает” и перестаёт занимать ресурсы процессора. При этом метод wait на время “сна” потока снимает блокировку с объекта obj, задаваемую оператором synchronized(obj). Что позволяет другим потокам обращаться к объекту с вызовом obj.notify() или obj.notifyAll().
- Содержание
- Глава 1. Общие представления о языке Java 6
- Глава 2. Объектно-ориентированное проектирование и платформа NetBeans 26
- Глава 3. Примитивные типы данных и операторы для работы с ними 78
- Глава 4. Работа с числами в языке Java 95
- Глава 5. Управляющие конструкции 112
- Глава 6. Начальные сведения об объектном программировании 128
- Глава 7. Важнейшие объектные типы 175
- Введение
- Глава 1. Общие представления о языке Java
- 1.1. Java и другие языки программирования. Системное и прикладное программирование
- 1.2. Виртуальная Java-машина, байт-код, jit-компиляция. Категории программ, написанных на языке Java
- 1.3.Алфавит языка Java. Десятичные и шестнадцатеричные цифры и целые числа. Зарезервированные слова Алфавит языка Java
- Десятичные и шестнадцатеричные цифры и целые числа
- Зарезервированные слова языка Java
- 1.4. Управляющие последовательности. Символы Unicode. Специальные символы Управляющие последовательности
- Простые специальные символы
- Составные специальные символы
- 1.5.Идентификаторы. Переменные и типы. Примитивные и ссылочные типы
- Краткие итоги по главе 1
- Задания
- Глава 2. Объектно-ориентированное проектирование и платформа NetBeans
- 2.1.Процедурное и объектно-ориентированное программирование. Инкапсуляция
- 2.2. Работа со ссылочными переменными. Сборка мусора
- 2.3. Проекты NetBeans. Пакеты. Уровни видимости классов. Импорт классов
- 2.4. Базовые пакеты и классы Java
- 2.5. Создание в NetBeans простейшего приложения Java
- 2.6. Компиляция файлов проекта и запуск приложения
- 2.7. Структура проекта NetBeans
- 2.8. Создание в NetBeans приложения Java с графическим интерфейсом
- 2.9. Редактор экранных форм
- 2.10. Внешний вид приложения
- 2.11. Ведение проектов
- 2.11. Редактирование меню экранной формы
- 2.12. Создание нового класса
- 2.13. Документирование исходного кода в Java
- 2.14. Основные компоненты пакетов swing и awt
- 2.15. Технологии Java и .Net
- Краткие итоги по главе 2
- Задания
- Глава 3. Примитивные типы данных и операторы для работы с ними
- 3.1.Булевский (логический) тип
- 3.2.Целые типы, переменные, константы
- 3.3.Основные операторы для работы с целочисленными величинами
- 3.4.Вещественные типы и класс Math
- 3.5.Правила явного и автоматического преобразования типа при работе с числовыми величинами
- 3.6. Оболочечные классы. Упаковка (boxing) и распаковка (unboxing)
- 3.7.Приоритет операторов
- 3.8.Типы-перечисления (enum)
- Краткие итоги по главе 3
- Задания
- Глава 4. Работа с числами в языке Java
- 4.1 Двоичное представление целых чисел Позиционные и непозиционные системы счисления
- Двоичное представление положительных целых чисел
- Двоичное представление отрицательных целых чисел. Дополнительный код
- Проблемы целочисленной машинной арифметики
- Шестнадцатеричное представление целых чисел и перевод из одной системы счисления в другую
- 4.2. Побитовые маски и сдвиги
- 4.3. Двоичное представление вещественных чисел Двоичные дроби
- Мантисса и порядок числа
- Стандарт ieee 754 представления чисел в формате с плавающей точкой*
- Краткие итоги по главе 4
- Задания
- Глава 5. Управляющие конструкции Составной оператор
- Условный оператор if
- Оператор выбора switch
- Условное выражение …?... : …
- Оператор цикла for
- Оператор цикла while – цикл с предусловием
- Оператор цикла do...While – цикл с постусловием
- Операторы прерывания continue, break, return, System.Exit
- Краткие итоги по главе 5
- Задания
- Глава 6. Начальные сведения об объектном программировании
- Наследование и полиморфизм. Uml-диаграммы
- Функции. Модификаторы. Передача примитивных типов в функции
- Локальные и глобальные переменные. Модификаторы доступа и правила видимости. Ссылка this
- Передача ссылочных типов в функции. Проблема изменения ссылки внутри подпрограммы
- Наследование. Суперклассы и подклассы. Переопределение методов
- Наследование и правила видимости. Зарезервированное слово super
- Статическое и динамическое связывание методов. Полиморфизм
- Базовый класс Object
- Конструкторы. Зарезервированные слова super и this. Блоки инициализации
- Удаление неиспользуемых объектов и метод finalize. Проблема деструкторов для сложно устроенных объектов
- Перегрузка методов
- Правила совместимости ссылочных типов как основа использования полиморфного кода. Приведение и проверка типов
- Рефакторинг
- Reverse engineering – построение uml-диаграмм по разработанным классам
- Краткие итоги по главе 6
- Задания
- Глава 7. Важнейшие объектные типы Массивы
- Коллекции, списки, итераторы
- Работа со строками в Java. Строки как объекты. Классы String, StringBuffer и StringBuilder
- Работа с графикой
- Исключительные ситуации Обработка исключительных ситуаций
- Иерархия исключительных ситуаций
- Объявление типа исключительной ситуации и оператор throw
- Объявление метода, который может возбуждать исключительную ситуацию. Зарезервированное слово throws
- Работа с файлами и папками
- Краткие итоги по главе 7
- Задания
- Глава 8. Наследование: проблемы и альтернативы. Интерфейсы. Композиция Проблемы множественного наследования классов. Интерфейсы
- Отличия интерфейсов от классов. Проблемы наследования интерфейсов
- Пример на использование интерфейсов
- Композиция как альтернатива множественному наследованию
- Краткие итоги по главе 8
- Задания
- Глава 9. Дополнительные элементы объектного программирования на языке Java Потоки выполнения (threads) и синхронизация
- Преимущества и проблемы при работе с потоками выполнения
- Синхронизация по ресурсам и событиям
- Класс Thread и интерфейс Runnable. Создание и запуск потока выполнения
- Поля и методы, заданные в классе Thread
- Подключение внешних библиотек dll.“Родные” (native) методы*
- Краткие итоги по главе 9
- Задания
- Глава 10. Введение в сетевое программирование Краткая справка по языку html
- Апплеты
- Сервлеты
- Технология jsp – Java Server Pages
- Краткие итоги по главе 10
- Задания
- Глава 11. Встроенные классы Виды встроенных классов
- Вложенные (nested) классы и интерфейсы
- Внутренние (inner) классы
- Локальные (local) классы
- Анонимные (anonimous) классы и обработчики событий
- Анонимные (anonimous) классы и слушатели событий (listeners)
- Краткие итоги по главе 11
- Задания
- Глава 12. Компонентное программирование Компонентная архитектура JavaBeans
- Мастер создания компонента в NetBeans
- Пример создания компонента в NetBeans – панель с заголовком
- Добавление в компонент новых свойств
- Добавление в компонент новых событий
- Краткие итоги по главе 12
- Задания
- Литература
- Дополнительная литература
- 276 Курс подготовлен при поддержке Sun Microsystems