Длинный примитив или AtomicLong для счетчика?
Мне нужен счетчик типа long
со следующими требованиями/фактами:
- Приращение счетчика должно занимать как можно меньше времени.
- Счетчик будет записываться только одним потоком.
- Чтение с счетчика будет выполнено в другом потоке.
- Счетчик будет регулярно увеличиваться (до нескольких тысяч раз в секунду), но будет читаться только раз в пять секунд.
- Точная точность не является существенной, только приблизительное представление о размере счетчика достаточно хорошее.
- Счетчик никогда не очищается, уменьшается.
Основываясь на этих требованиях, как бы вы решили реализовать свой счетчик? Как простой long
, как volatile long
или используя AtomicLong
? Почему?
На данный момент у меня есть volatile long
, но мне было интересно, будет ли другой подход лучше. Я также увеличиваю свое время, выполняя ++counter
, а не counter++
. Действительно ли это действительно более эффективно (как меня верили в другое место), потому что не выполняются задания?
Заранее спасибо
Рич
Ответы
Ответ 1
Учитывая эти наборы требований, я думаю, что a volatile
long должно быть достаточным. Счетчик не был бы неправильным с длиной не менее volatile
, но читатель мог бы читать устаревшую информацию в этом случае.
Одна проблема заключается в том, что чтение и запись в long
не требуется для атомарного, спецификация JVM, если она не объявлена volatile
. Это означало бы, что поток чтения может получить довольно фиктивное значение, если он считывает значение, в то время как поток записи обновляет одну часть значения, но не другую.
Разница между ++counter
и counter++
, вероятно, не имеет значения, поскольку JVM поймет, что значение выражения больше не используется, а два эквивалентны в этом случае.
Ответ 2
В Java 8 используйте LongAdder, который даже лучше AtomicLong, где конфликт потоков высок.
LongAdder JavaDoc:
Этот класс обычно предпочтительнее AtomicLong, когда несколько потоков обновляют общую сумму, которая используется для целей сбора статистики, а не для мелкомасштабного управления синхронизацией. В условиях низкого уровня обновления два класса имеют схожие характеристики. Но при высокой конкуренции ожидаемая пропускная способность этого класса значительно выше за счет более высокого потребления пространства.
Ответ 3
какое время ожидания для вашей программы? Не могли бы вы поработать с нестабильным int и racy-reads?
Ответ 4
10 ^ 4 с шагом в секунду - 1 каждые 100 мкс. Эффективность - это не проблема, но атомарность может быть. У вас может быть 2 копии, и когда он будет прочитан, если они не равны, прочитайте снова.
Ответ 5
В этой статье говорится о возможных способах реализации счетчика
Я думаю, что эта реализация должна работать для вас.
class LessNaiveVolatieIdGenerator {
private static volatile long id = 0;
public static long nextId() {
long nextId = (id = id + 1); // or nextId = id++;
return nextId;
}
}