Какие механизмы Java вы используете для реализации потокобезопасного счетчика?

«Какие механизмы Java вы используете для реализации потокобезопасного счетчика?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для реализации потокобезопасного счетчика в Java есть несколько основных подходов, выбор зависит от требуемой функциональности и производительности.

Механизм Когда использовать Пример
AtomicInteger Для простых атомарных операций (инкремент, декремент). Наиболее эффективный и предпочтительный вариант для счетчика. ```java

AtomicInteger counter = new AtomicInteger(0); int newValue = counter.incrementAndGet(); // Потокобезопасно


| **`synchronized`** | Когда операция не сводится к одной атомарной команде (например, нужно проверить условие перед изменением). | ```java
private int count = 0;
public synchronized void incrementIfLessThan(int max) {
    if (count < max) {
        count++;
    }
}
``` |
| **`ReentrantLock`** | Когда требуется более гибкое управление блокировкой: попытка захвата (`tryLock()`), честность (fairness), привязка условий. | ```java
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
    lock.lock();
    try {
        count++;
    } finally {
        lock.unlock(); // Важно освобождать в finally
    }
}
``` |

**Рекомендация:** Для типичного счетчика всегда выбирайте **`AtomicInteger`**. Классы из пакета `java.util.concurrent.atomic` используют аппаратные инструкции сравнения-и-обмена (CAS), что обеспечивает высокую производительность без явных блокировок.