AtomicInteger与Integer的性能差异

Bon*_*oni 13 java concurrency

有没有之间的性能差异AtomicIntegerInteger

tun*_*2fs 15

这两种类型的选择不应取决于性能.主要的选择AtomicInteger是,如果你想通过整数运算来实现线程安全.

但是,性能差异可能很大程度上取决于选择的操作系统,因为原子操作的详细实现取决于操作系统.

  • +1.即使在非并发用例中,AtomicInteger也提供廉价的可变整数. (4认同)
  • @MichaelBorgwardt:OP的问题甚至没有提到多线程.他只是询问Integer和AtomicInteger之间是否存在性能差异.尚未创建AtomicInteger以获得更快的Integer.它的创建是为了提供一个线程安全,无锁,可变的Integer.如果您不需要可变性并且不在多线程环境中执行,那么两者的性能无关紧要.您选择最合适的类型:整数.只有在需要可变性(和线程安全性)时才应考虑AtomicInteger. (4认同)
  • @MichaelBorgwardt:只是因为只有同步才能实现线程安全并不意味着AtomicInteger不提供线程安全整数操作.答案的要点是Integer和AtomicInteger的原始性能不是指导其中一个或另一个的选择.选择的指导是预期的用法:我们需要一个可变的线程安全整数,还是我们只想将一个整数说成一个不可变的对象? (2认同)

Mic*_*rdt 11

AtomicInteger允许一些(不是全部!)操作,否则需要使用特殊硬件指令以无锁方式执行同步.这对性能的影响有些复杂:

  • 首先,它是一种微优化,只有当这个特定操作在您的应用程序的关键路径上时才会有效.
  • 特殊硬件指令可能在非主流平台上不可用,在这种情况下AtomicInteger可能会使用同步实现.
  • 当没有争用时,JVM通常可以优化掉锁定开销(例如,单线程应用程序).在那种情况下,可能没有区别.
  • 如果存在低到中等的锁争用(即多个线程,但它们主要做除了访问该整数之外的其他事情),则无锁算法比同步更好.
  • 如果存在非常大的锁争用(即大量线程花费大量时间尝试访问该整数),则同步可能表现更好,因为无锁算法基于在由于冲突而失败时不断重试操作.

  • 正是我一直在寻找的事实类型.谢谢. (4认同)

bpg*_*rgo 10

好吧,如果你在多线程环境中使用它,例如计数器,那么你必须synchronize访问整数

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

  public synchronized long increment() {
    return ++value;
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然您可以在没有同步的情况下使用AtomicInteger获得更好的性能

public class NonblockingCounter {
    private AtomicInteger value;

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

    public int increment() {
        return value.incrementAndGet();
    }
}
Run Code Online (Sandbox Code Playgroud)

推荐阅读http://cephas.net/blog/2006/09/06/atomicinteger/

编辑使用incrementAndGet


Jav*_*aJd 5

今天看到这个帖子,但想分享我的结果(请不要对代码发表评论,因为我必须手动输入以下类,因为我运行这个类的系统没有连接到互联网 :)

下面代码的输出结果如下:

ATOMIC 结果:Elapsed = 25257 ms,ExpectedValue = 50000,FinalValue = 50000,true PrImItIvE 结果:Elapsed = 25257 ms,ExpectedValue = 50000,FinalValue = 48991,false

对于我在特定应用程序中的使用,我选择在监控类中使用原子值作为状态编号。如果其他人想查看一些困难的结果,我选择发布此信息。

祝你有美好的一天!

课程:

我创建了一个主类,其中包含一个原始 long 和一个原子 long 以及访问器增量方法、一个 IncrementAtomicRunnable 和一个 IncrementPrimitiveRunnable。

长开销:

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)));
  }
Run Code Online (Sandbox Code Playgroud)

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.");
  }
}
Run Code Online (Sandbox Code Playgroud)

最后是 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.");
  }
}
Run Code Online (Sandbox Code Playgroud)