Разница в производительности AtomicInteger против Integer - PullRequest
12 голосов
/ 16 января 2012

Есть ли разница в производительности между AtomicInteger и Integer?

Ответы [ 5 ]

15 голосов
/ 16 января 2012

Выбор этих двух типов не должен зависеть от производительности.Основной выбор для AtomicInteger - это если вы хотите добиться безопасности потоков с помощью операций с целым числом.

Однако разница в производительности может сильно зависеть от выбранной операционной системы, поскольку детальная реализация атомарных операций зависит отоперационная система.

9 голосов
/ 16 января 2012

AtomicInteger разрешает некоторые (не все!) Операции, которые в противном случае потребовали бы, чтобы синхронизация выполнялась без блокировки с использованием специальных аппаратных инструкций. Как это влияет на производительность, довольно сложно:

  • Во-первых, это микрооптимизация, которая будет иметь значение, только если эта конкретная операция находится на критическом пути вашего приложения.
  • Специальные аппаратные инструкции могут быть недоступны на неосновных платформах, и в этом случае AtomicInteger, вероятно, будет реализовано с использованием синхронизации.
  • JVM часто может оптимизировать затраты на блокировку, когда нет конфликтов (например, однопоточное приложение). В этом случае, вероятно, нет никакой разницы.
  • Если конкуренция за блокировку от низкой до умеренной (т. Е. Множественные потоки, но в большинстве случаев они выполняют не только доступ к этому целому числу), алгоритм без блокировки работает лучше, чем синхронизация.
  • Если существует очень сильная конкуренция за блокировку (т. Е. Много потоков, которые тратят много времени, пытаясь получить доступ к этому целому числу), синхронизация может работать лучше, потому что алгоритм без блокировки основан на постоянной повторной попытке операции в случае сбоя из-за столкновение.
9 голосов
/ 16 января 2012

Что ж, если вы используете его в многопоточной среде, например, в качестве счетчика, то вам нужно synchronize получить доступ к Integer

public final class Counter {
  private long value = 0;
  public synchronized long getValue() {
    return value;
  }

  public synchronized long increment() {
    return ++value;
  }
}

Хотя вы можете добиться гораздо лучшей производительности с AtomicInteger без синхронизации

public class NonblockingCounter {
    private AtomicInteger value;

    public int getValue() {
        return value.get();
    }

    public int increment() {
        return value.incrementAndGet();
    }
}

Рекомендуемое чтение http://cephas.net/blog/2006/09/06/atomicinteger/

РЕДАКТИРОВАТЬ использовать incrementAndGet

2 голосов
/ 28 июня 2017

Сегодня наткнулся на эту публикацию, но хотел поделиться своими результатами (Пожалуйста, не комментируйте код, так как мне пришлось вручную вводить следующие классы, так как система, на которой я работал, не была подключена к Интернету:)

В итоге вывод кода ниже был следующим:

Результаты ATOMIC: истек = 25257 мс, ожидаемое значение = 50000, конечное значение = 50000, верно Предварительные результаты: истек = 25257 мс, ожидаемое значение = 50000, конечное значение = 48991, ложь

Для моего использования в моем конкретном приложении я решил использовать атомарные значения для номеров статуса в классе мониторинга. На случай, если кто-то еще захочет просмотреть какие-то трудные результаты, я решил опубликовать эту информацию.

Хорошего дня!

Классы:

Я создал основной класс с примитивным long и атомарным long и методами приращения accessor, IncrementAtomicRunnable и IncrementPrimitiveRunnable.

LongOverhead:

public class LongOverhead{
  AtomicLong atomicLong;
  long primitiveLong;

  public LongOverhead(){
    atomicLong = new AtomicLong(0l);
    primitiveLong = 0l;
  }

  public void incrAtomicLong(){
    atomicLong.getAndAdd(1l);
  }

  public long getAtomicLong(){
    return atomicLong.get();
  }

  public void incrPrimitiveLong(){
    primitiveLong++;
  }

  public long getPrimitiveLong(){
    return primitiveLong;
  }

  public static void main(String [] args){
    String template = "%s Results:  Elapsed = %d ms, ExpectedValue = %d, FinalValue = %d, %b";

    int loopTotal = 1000;
    int waitMilliseconds = 25;
    int totalThreads = 50;
    int expectedValue = loopTotal * totalThreads;
    int whileSleep = 250;

    LongOverhead atomic = new LongOverhead();
    LongOverhead primitive = new LongOverhead();

    List<Thread> atomicThreads = new ArrayList<>();
    List<Thread> primitiveThreads = new ArrayList<>();

    for(int x=0;x<totalThreads;x++){
      Thread a = new Thread(new IncrementalAtomicRunnable(atomic, loopTotal, waitMilliseconds), "AtomicIncr" + x);
      atomicThreads.add(a);

      Thread p = new Thread(new IncrementalPrimitiveRunnable(primitive, loopTotal, waitMilliseconds), "PrimitiveIncr" + x);
      primitiveThreads.add(p);
    }

    boolean cont = true;
    long atomicStart = System.currentTimeMillis();
    for(Thread t:  atomicThreads){
      t.start();
    }

    while(cont){
      try{
        Thread.sleep(whileSleep);
      }catch(InterruptedException e){
         e.printStackTrace();
      }

      boolean foundAlive = false;
      for(Thread t: atomicThreads){
        foundAlive = (State.TERMINATED != t.getState());
        if(foundAlive){
          break;
        }
      }

      cont = foundAlive;

    }

    long atomicFinish = System.currentTimeMillis();
    long atomicElapsed = atomicFinish - atomicStart;
    long atomicFinal = atomic.getAtomicLong();

    cont = true;
    long primitiveStart = System.currentTimeMillis();
    for(Thread t:  primitiveThreads){
      t.start();
    }

    while(cont){
      try{
        Thread.sleep(whileSleep);
      }catch(InterruptedException e){
         e.printStackTrace();
      }

      boolean foundAlive = false;
      for(Thread t: primitiveThreads){
        foundAlive = (State.TERMINATED != t.getState());
        if(foundAlive){
          break;
        }
       }

       cont = foundAlive;
    long primitiveFinish = System.currentTimeMillis();
    long primitiveElapsed = primitiveFinish - primitiveStart;
    long primitiveFinal = primitive.getPrimitiveLong();

    System.out.println(String.format(template, "ATOMIC", atomicElapsed, expectedValue, atomicFinal, (expectedValue==atomicFinal)));
    System.out.println(String.format(template, "PrImItIvE", primitiveElapsed, expectedValue, primitiveFinal, (expectedValue==primitiveFinal)));
  }

IncrementAtomicRunnable:

public class IncrementAtomicRunnable implements Runnable{
  protected LongOverhead oh;
  protected int loopTotal;
  protected int waitMilliseconds;
  protected String currentThreadName;

  public IncrementAtomicRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){
    this.oh = oh;
    this.loopTotal = loopTotal;
    this.waitMilliseconds = waitMilliseconds;
  }

  @Override
  public void run(){
    currentThreadName = Thread.currentThread().getName();
    System.out.println(currentThreadName + " for ATOMIC is starting.....");
    for(int x=0;x<loopTotal;x++){
      oh.incrAtomicLong();
      try{
        Thread.sleep(waitMilliseconds);
      }catch(InterruptedException e){
        System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@");
      }
    }

    System.out.println("....." + currentThreadName + " for ATOMIC is finished.");
  }
}

и наконец IncrementPrimitiveRunnable:

public class IncrementPrimitiveRunnable extends IncrementAtomicRunnable{
  public IncrmentPrimitiveRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){
    super(oh, loopTotal, waitMilliseconds);
  }

  @Override
  public void run(){
    super.currentThreadName = Thread.currentThread().getName();
    System.out.println(currentThreadName + " for PRIMITIVE is starting.....");
    for(int x=0;x<loopTotal;x++){
      oh.incrPrimitiveLong();
      try{
        Thread.sleep(waitMilliseconds);
      }catch(InterruptedException e){
        System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@");
      }
    }

    System.out.println("....." + currentThreadName + " for PRIMITIVE is finished.");
  }
}
2 голосов
/ 16 января 2012

За исключением очень незначительных накладных расходов на синхронизацию, нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...