2012-01-16 4 views

ответ

13

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

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

+3

+1. AtomicInteger также обеспечивает дешевое изменяемое целое число, даже в неконкурентном случае использования. –

+0

-1: AtomicInteger существует в основном по причине производительности (для реализации блокировки данных). Если бы ваша безопасность была единственной проблемой, вы могли бы просто использовать синхронизацию. –

+2

@MichaelBorgwardt: просто потому, что безопасность потоков возможна только при синхронизации, это не означает, что AtomicInteger не обеспечивает поточно-безопасные операции с целыми числами. Суть ответа заключается в том, что необработанная производительность Integer и AtomicInteger не является тем, что определяет выбор того или другого. Каким направлением выбора является предполагаемое использование: нужно ли нам использовать изменяемое целое число, защищенное потоками, или мы просто хотим рэп целое число в неизменяемый объект? –

1

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

5

Ну, если вы используете его в многопоточной среде, например, как, например, счетчик, то вы должны 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/

EDIT использование incrementAndGet

+0

Почему бы не использовать incrementAndGet? –

+0

Вы имеете в виду [getAndIncrement] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html#getAndIncrement())? Ну, хороший вопрос, сэр, наверное, я был слишком быстр и ленив. – bpgergo

+0

Нет, я имею в виду incrementAndGet. getAndIncrement будет эквивалентно возврату i ++. Но ваш первый фрагмент returnn ++ i; –

3

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

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

Точно такие типы фактов, которые я искал. Благодарю. –

0

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

Нижняя линия выход из кода ниже следующим образом:

ATOMIC Результаты: Истекшее = 25257 мс, ExpectedValue = 50000, FinalValue = 50000, истинные примитивного Результаты: Прошедшее = 25257 мс, ExpectedValue = 50000, FinalValue = 48991, false

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

Отличный день!

Классы:

Я создал основной класс с примитивными долго и атомными длинными и аксессорами методами приращения, в 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."); 
    } 
} 
Смежные вопросы