Лично я считаю, что решение AtomicInteger
немного уродливо, поскольку оно вводит условие гонки, которое означает, что ваша попытка обновления может "провалиться" и должна быть повторена (путем итерации внутри цикла while), делая время обновления менее детерминированным чем выполнение всей операции в критической секции.
Написание собственного счетчика настолько тривиально, что я бы рекомендовал такой подход. Это также лучше с точки зрения ОО, так как оно показывает только те операции, которые вам разрешено выполнять.
public class Counter {
private final int max;
private int count;
public Counter(int max) {
if (max < 1) { throw new IllegalArgumentException(); }
this.max = max;
}
public synchronized int getCount() {
return count;
}
public synchronized int increment() {
count = (count + 1) % max;
return count;
}
}
EDIT
Другая проблема, с которой я столкнулся при решении цикла while, заключается в том, что, учитывая большое количество потоков, пытающихся обновить счетчик, вы можете столкнуться с ситуацией, когда у вас вращается несколько потоков и пытается обновить счетчик. Учитывая, что только 1 поток будет успешным, все другие потоки будут сбои, что приведет к их итерации и потере циклов ЦП.