Проблема: проверка-then-действие неатомарна — между `if (c < 10)` и `c++` другой поток может изменить `c`, что ведёт к условной гонке. Короткое и корректное решение — использовать атомарные операции. Два варианта (правильно и эффективно): 1) Простая синхронизация (корректно, но при высокой нагрузке — блокировка): // начальное c = 000, предел = 101010
class Counter { private int c = 0; public synchronized boolean inc() { if (c < 10) { c++; return true; } return false; } public synchronized int get() { return c; } } 2) Неблокирующий и более производительный вариант — AtomicInteger (атомарная функция): // начальное c = 000, предел = 101010
import java.util.concurrent.atomic.AtomicInteger; class Counter { private final AtomicInteger c = new AtomicInteger(0); // возвращает true, если увеличили public boolean inc() { return c.updateAndGet(x -> x < 10 ? x + 1 : x) 0; // можно проще вернуть флаг по значению до/после; см. вариант с CAS ниже } public int get() { return c.get(); } } Практичнее и яснее — CAS-цикл, возвращающий успех: class Counter { private final AtomicInteger c = new AtomicInteger(0); public boolean inc() { while (true) { int prev = c.get(); if (prev >= 10) return false; if (c.compareAndSet(prev, prev + 1)) return true; } } public int get() { return c.get(); } } Почему предпочтительно AtomicInteger: - Операции неблокирующие (лучше масштабируются при высокой конкуренции). - Обеспечивается атомарность проверки и инкремента без внешней синхронизации. Выбор: если конкуренция низкая и код проще — synchronized; при высокой нагрузке — CAS/AtomicInteger.
Короткое и корректное решение — использовать атомарные операции. Два варианта (правильно и эффективно):
1) Простая синхронизация (корректно, но при высокой нагрузке — блокировка):
// начальное c = 000, предел = 101010 class Counter {
private int c = 0;
public synchronized boolean inc() {
if (c < 10) { c++; return true; }
return false;
}
public synchronized int get() { return c; }
}
2) Неблокирующий и более производительный вариант — AtomicInteger (атомарная функция):
// начальное c = 000, предел = 101010 import java.util.concurrent.atomic.AtomicInteger;
class Counter {
private final AtomicInteger c = new AtomicInteger(0);
// возвращает true, если увеличили
public boolean inc() {
return c.updateAndGet(x -> x < 10 ? x + 1 : x) 0;
// можно проще вернуть флаг по значению до/после; см. вариант с CAS ниже
}
public int get() { return c.get(); }
}
Практичнее и яснее — CAS-цикл, возвращающий успех:
class Counter {
private final AtomicInteger c = new AtomicInteger(0);
public boolean inc() {
while (true) {
int prev = c.get();
if (prev >= 10) return false;
if (c.compareAndSet(prev, prev + 1)) return true;
}
}
public int get() { return c.get(); }
}
Почему предпочтительно AtomicInteger:
- Операции неблокирующие (лучше масштабируются при высокой конкуренции).
- Обеспечивается атомарность проверки и инкремента без внешней синхронизации.
Выбор: если конкуренция низкая и код проще — synchronized; при высокой нагрузке — CAS/AtomicInteger.