Проект 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 Билла Бекака в блоге « Случайные мысли о кодировании» .