Статьи

Google Guava — синхронизация с монитором

Проект 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 чтобы эффективно охватить их в одном посте, поэтому я собираюсь выбрать первые три и представить их по порядку от минимальной блокировки до максимальной.

    1. tryEnterIf — потоки не будут ждать входа в монитор и будут входить только в том случае, если условие охраны возвращает true.
    2. enterIf — потоки будут ожидать входа в монитор, но только если условие охраны возвращает true. Существуют также сигнатуры метода enterIf, которые позволяют указать время ожидания, а также версия enterIfInterruptibly .
    3. enterWhen — потоки будут бесконечно ждать, пока монитор и условие вернут истину, но могут быть прерваны. Аналогичным образом, есть варианты указания тайм-аутов, а также версия enterWhenUrribbly .

Вывод

У меня еще не было возможности использовать монитор на работе, но я вижу полезность в детализации условий логической защиты. Я написал несколько базовых примеров кода и сопровождающий модульный тест, которые демонстрируют некоторые функции, описанные в этом посте. Они доступны здесь . Как всегда, ваши комментарии / предложения приветствуются. В моем следующем посте я расскажу больше о том, что можно найти в параллелизме гуавы.

Ресурсы

    Справка: Google Guava — Синхронизация с монитором от нашего партнера по JCG Билла Бекака в блоге « Случайные мысли о кодировании» .