Как внутренне работает метод incrementAndGet для AtomicLong?
Я использую incrementAndGet
метод AtomicLong
в моем многопоточном коде, чтобы измерить производительность некоторого нашего клиентского кода.
@Override
public void run() {
long start = System.nanoTime();
attributes = client.getAttributes(columnsList);
long end = System.nanoTime() - start;
final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
if (before != null) {
before.incrementAndGet();
}
}
В приведенном выше коде я пытаюсь измерить, сколько времени
client.getAttributes(columnsList);
принимает.
Насколько я знаю incrementAndGet
Метод будет увеличивать текущее значение на единицу атомарным способом. Это означает, что, возможно, каждый поток будет ожидать, пока другие потоки увеличат значение. Я прав? Имеется в виду, что это будет заблокировано?
И также это влияет на то, как я измеряю производительность любого метода? То есть это добавит дополнительное время к этому измерению?
Почему я спрашиваю об этом, потому что я пытаюсь сравнить большую часть нашего клиентского кода и серверного кода, и если мне нужно измерить, сколько времени занимает каждый метод, я делаю это просто так:
Какой бы код я не хотел измерить, я обычно помещаю строку ниже чуть выше этого метода
long start = System.nanoTime();
И эти две строки после того же метода, но с разными ConcurrentHashMap
long end = System.nanoTime() - start;
final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
if (before != null) {
before.incrementAndGet();
}
Так что, если я использую incrementAndGet
метод, и если это добавляет дополнительное время к моим измерениям производительности, то возможно, что я не получаю точный результат?
Обновить:-
Это метод ниже, я получил, когда я сделал F3
на incrementAndGet
в eclipse
,
Так что здесь есть синхронизированный блок. Это означает, что каждый поток будет ждать здесь других потоков. И это блокирующий звонок.
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final synchronized long incrementAndGet() { //IBM-perf_AtomicLong
++value; //IBM-perf_AtomicLong
return value; //IBM-perf_AtomicLong
}
Ааа. Я только что проверил свою JVM, и я бегу IBM JVM
по сравнению с SUN JVM
, Поскольку я работаю в компании, где я не могу изменить эту конкретную вещь.
Так есть ли способ избежать этого решения на основе блокировки, чтобы измерить производительность / эталон любого метода? Помня, что я использую IBM JVM.
Спасибо за помощь.
1 ответ
Просто не волнуйся. Если вы не пишете что-то вроде платформы Forex или чего-то такого, эта крошечная задержка не будет иметь значения. Чтобы дать вам представление, мы будем говорить в порядке наносекунд, тогда как в коде приложения мы обычно говорим в миллисекундах. Кроме того, блокировки JVM значительно улучшились. Если у вас низкий уровень конкуренции (что является нормой), разница в производительности между решением на основе блокировки и неблокирующим решением будет крошечной.
Удивительно, что IBM JVM использует блокировку для AtomicLong. Я думал, что все основные реализации используют неблокирующие CAS. Вот общая реализация, которая использует CAS:
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final long incrementAndGet() {
for (;;) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
Ответ на последующий комментарий:
Как очень грубое практическое правило, если ваше текущее сквозное время отклика (или требование времени отклика) превышает 30 мс, я бы на самом деле не беспокоился об этом, поскольку любое время, потраченное на увеличение длинны, было бы в сфере наносекунд, Я почти уверен, что вы найдете другие места для оптимизации, которые дадут вам больше улучшений (например, миллисекунды).
Однако вы можете просто скопировать реализацию AtomicLong Sun JVM, чтобы использовать вместо этого неблокирующую реализацию, поскольку IBM VM также должна иметь операции CAS. Это может привести к значительному улучшению только в том случае, если вы ожидаете умеренного или высокого уровня конкуренции (много потоков). Если вы этого не сделаете, я думаю, что решение по блокировке может работать почти идентично с текущей улучшенной реализацией блокировки (доступно из JDK6, если я помню).
На самом деле, если у вас очень высокий уровень конкуренции, блокировка может выполнить ЛУЧШЕ, чем неблокирующее решение. Таким образом, в идеале вам нужно использовать две реализации и сравнить результаты... вот почему я думаю, что вам не стоит беспокоиться, потому что за это время вы могли бы сделать несколько улучшений производительности в другом месте, что дает вам литературный больше, чем 1 Миллион раз улучшение, которое вы могли бы достичь путем решения здесь.