Проект Google Guava — это набор библиотек, с которыми должен ознакомиться каждый разработчик Java. Библиотеки Guava охватывают ввод-вывод, коллекции, манипуляции со строками и параллелизм, и это лишь некоторые из них. В этом посте я собираюсь рассказать о классе Monitor. Монитор — это конструкция синхронизации, которую можно использовать везде, где вы используете ReentrantLock. Только один поток может занимать монитор в любое время. Класс Monitor имеет операции входа и выхода, которые семантически совпадают с операциями блокировки и разблокировки в ReentrantLock. Кроме того, монитор поддерживает ожидание в логических условиях.
Сравнение монитора и ReentrantLock
Для начала было бы полезно провести параллельное сравнение Monitor и ReentrantLock.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
public class ReentrantLockSample { private List<String> list = new ArrayList<String>(); private static final int MAX_SIZE = 10 ; private ReentrantLock rLock = new ReentrantLock(); private Condition listAtCapacity = rLock.newCondition(); public void addToList(String item) throws InterruptedException { rLock.lock(); try { while (list.size() == MAX_SIZE) { listAtCapacity.await(); } list.add(item); } finally { rLock.unlock(); } } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public class MonitorSample { private List<String> list = new ArrayList<String>(); private static final int MAX_SIZE = 10 ; private Monitor monitor = new Monitor(); private Monitor.Guard listBelowCapacity = new Monitor.Guard(monitor) { @Override public boolean isSatisfied() { return (list.size() < MAX_SIZE); } }; public void addToList(String item) throws InterruptedException { monitor.enterWhen(listBelowCapacity); try { list.add(item); } finally { monitor.leave(); } } } |
Как видно из примера, оба кода имеют практически одинаковое количество строк кода. Monitor
добавляет некоторую сложность вокруг объекта Guard
по сравнению с ReentrantLock Condition
. Однако ясность метода addToList
в Monitor
более чем компенсирует это. Это может быть моим личным предпочтением, но я всегда находил
1
2
3
|
while (something== true ){ condition.await() } |
быть немного неловким
Правила использования
Следует отметить, что методы enter
, возвращающие void
всегда должны принимать вид:
1
2
3
4
5
6
|
monitor.enter() try { ...work.. } finally { monitor.leave(); } |
и enter
методы, которые возвращают boolean
должно выглядеть так:
1
2
3
4
5
6
7
8
9
|
if (monitor.enterIf(guard)){ try { ...work.. } finally { monitor.leave(); } } else { .. monitor not available.. } |
Булевы условия
В классе Monitor слишком много методов enter
чтобы эффективно охватить их в одном посте, поэтому я собираюсь выбрать первые три и представить их по порядку от минимальной блокировки до максимальной.
- tryEnterIf — потоки не будут ждать входа в монитор и будут входить только в том случае, если условие охраны возвращает true.
- enterIf — потоки будут ожидать входа в монитор, но только если условие охраны возвращает true. Существуют также сигнатуры метода enterIf, которые позволяют указать время ожидания, а также версия enterIfInterruptibly .
- enterWhen — потоки будут бесконечно ждать, пока монитор и условие вернут истину, но могут быть прерваны. Аналогичным образом, есть варианты указания тайм-аутов, а также версия enterWhenUrribbly .
Вывод
У меня еще не было возможности использовать монитор на работе, но я вижу полезность в детализации условий логической защиты. Я написал несколько базовых примеров кода и сопровождающий модульный тест, которые демонстрируют некоторые функции, описанные в этом посте. Они доступны здесь . Как всегда, ваши комментарии / предложения приветствуются. В моем следующем посте я расскажу больше о том, что можно найти в параллелизме гуавы.
Ресурсы
Справка: Google Guava — Синхронизация с монитором от нашего партнера по JCG Билла Бекака в блоге « Случайные мысли о кодировании» .