«1. Введение

В предыдущей статье мы начали изучать новую функциональность, представленную в пакете common.collect.

В этой быстрой статье давайте рассмотрим дополнения к пакету common.util.concurrent.

2. AtomicLongMap

В параллельных сценариях стандартный HashMap может работать не очень хорошо, поскольку он просто не является параллельным. В этом конкретном сценарии AtomicLongMap выручает вас, сохраняя значения Long потокобезопасным способом.

AtomicLongMap был представлен давным-давно в Guava 11. Теперь были добавлены четыре новых метода.

2.1. accumulationAndGet()

Метод accumulatorAndGet() обновляет значение, связанное с ключом, объединяя его с существующим значением с помощью функции аккумулятора. Затем он возвращает обновленное значение:

@Test
public void accumulateAndGet_withLongBinaryOperator_thenSuccessful() {
    long noOfStudents = 56;
    long oldValue = courses.get(SPRING_COURSE_KEY);

    long totalNotesRequired = courses.accumulateAndGet(
      "Guava", 
      noOfStudents, 
      (x, y) -> (x * y));

    assertEquals(totalNotesRequired, oldValue * noOfStudents);
}

2.2. getAndAccumulate()

Этот метод имеет аналогичную функциональность, как определено выше, но он возвращает старое значение вместо обновленного значения (как предполагает порядок операций в том же).

2.3. updateAndGet()

Метод updateAndGet() обновляет текущее значение ключа, используя указанную функцию, указанную в качестве второго параметра. Затем возвращает обновленное значение ключа:

@Test
public void updateAndGet_withLongUnaryOperator_thenSuccessful() {
    long beforeUpdate = courses.get(SPRING_COURSE_KEY);
    long onUpdate = courses.updateAndGet(
      "Guava",
      (x) -> (x / 2));
    long afterUpdate = courses.get(SPRING_COURSE_KEY);

    assertEquals(onUpdate, afterUpdate);
    assertEquals(afterUpdate, beforeUpdate / 2);
}

2.4. getAndUpdate()

Этот метод работает очень похоже на updateAndGet(), но возвращает старое значение ключа, а не обновленное.

3. Монитор

Класс монитора считается заменой ReentrantLock, кроме того, он немного более удобочитаем и менее подвержен ошибкам.

3.1. Monitor.newGuard()

В Guava 21 добавлен новый метод — newGuard() — который возвращает экземпляр Monitor.Guard, служит логическим условием, которого может ожидать поток:

public class MonitorExample {
    private List<String> students = new ArrayList<String>();
    private static final int MAX_SIZE = 100;

    private Monitor monitor = new Monitor();

    public void addToCourse(String item) throws InterruptedException {
        Monitor.Guard studentsBelowCapacity = monitor.newGuard(this::isStudentsCapacityUptoLimit);
        monitor.enterWhen(studentsBelowCapacity);
        try {
            students.add(item);
        } finally {
            monitor.leave();
        }
    }

    public Boolean isStudentsCapacityUptoLimit() {
        return students.size() > MAX_SIZE;
    }
}

4. MoreExecutors

В этом классе нет дополнений, но API sameThreadExecutor() удален. Этот метод устарел, начиная с версии 18.0, и вместо него рекомендуется использовать directExecutor() или newDirectExecutorService().

5. ForwardingBlockingDeque

ForwardingBlockingDeque — это существующий класс, который был перемещен из common.collect, поскольку BlockingQueue больше похож на тип параллельной коллекции, чем на стандартную коллекцию.

6. Заключение

Guava 21 не только пытается представить новые утилиты, чтобы идти в ногу с Java 8, но и улучшить существующую модель, чтобы сделать ее более значимой.

И, как всегда, примеры кода в этой статье доступны в репозитории GitHub.