Блокировки и условия — мощный инструмент синхронизации потоков, но они не слишком объектно-ориентированы. В течении многих лет исследователи ищут способы обеспечения безопасности многопоточности, дабы избавить программистов от необходимости думать о явных блокировках.
Одно из наиболее успешных решений — концепция монитора, которая была впервые предложена Петром Бринчем Хансеном(Per Brinch Hansen) и Тони Хоаром(Tony Hoare) в 70-х годах. В терминологии Java монитор обладает перечисленными ниже свойствами.
- Монитор — это класс, имеющий только приватные поля.
- Каждый объект этого класса имеет ассоциированную с ним блокировку.
- Все методы блокируются этой блокировкой. Другими словами, если клиент вызывает obj.method(), то при этом автоматически запирается блокировка объекта obj в начале метода и освобождается по его завершении. Поскольку все поля приватные, такой подход гарантирует, что ни один поток не сможет обратиться к ним, пока ими манипулирует какой-то другой поток.
- Блокировка может иметь любое количество ассоциированных условий.
Ранние версии монитора имели единственное условие, с достаточно элегантным синтаксисом. Вы можете просто вызвать await accounts[from] >= balance, не используя явно условную переменную. Однако исследование показали, что неразборчивая повторная проверка условий может оказаться неэффективной. Проблема была решена применением явных переменных условий, каждая из которых управляет отдельным набором потоков.
Проектировщики Java вольно адаптировали концепцию монитора. Каждый объект в Java обладает внутренной блокировкой и внутренним условием. Если метод объявлен с ключевым словом synchronized, он работает как метод монитора. Переменная условия доступна через вызовы wait/notifyAll/notify.
Однако объекты Java отличаются от мониторов в трех важных отношениях, ослабляющих безопасность потоков.
- Поля не обязательно должны быть private.
- Методы не обязаны быть synchronized.
- Внутренняя блокировка доступна клиентам.
Это — явное пренебрежение требованиями безопасности, изложенными Пером Бринчем Хансеном. В уничижительном обозрении, посвященном примитивам многозадачности Java, он пишет: «Для меня является непостижимым тот факт, что небезопасный параллелизм столь серьезно принят сообществом программистов, и это спустя четверть века после изобретения мониторов и языка Concurrent Pascal. Этому нет оправданий».