Is there any performance difference between AtomicInteger
and Integer
?
5 Answers
The choice of these two types should not depend on the performance. The main choice for AtomicInteger
is if you want to achieve thread safety with the operations on the integer.
However the performace difference might strongly depend on the choosen operating system, as the detailed implementation of atomic operations depend on the operating system.
-
4+1. AtomicInteger also provide a cheap mutable integer, even in a non-concurrent use-case. – JB Nizet Jan 16 '12 at 10:43
-
-1: AtomicInteger exists mainly for performance reason (to implement lock-free data structures). If thead safety were the only concern, you could simply use synchronization. – Michael Borgwardt Jan 16 '12 at 10:57
-
2@MichaelBorgwardt: just because thread-safety is possible with just synchronization doesn't mean that AtomicInteger doesn't provide thread-safe integer operations. The point of the answer is that the raw performance of Integer and AtomicInteger is not what guides the choice of one or the other. What guides the choice is the intended usage: do we need a mutable thread-safe integer, or do we simply want to rap an integer into an immutable object? – JB Nizet Jan 16 '12 at 11:11
-
@JB Nizet: mutability is not mentioned in the answer. And apart from that, how can performance not be what guides the choice when one of the choices exists because of performance? – Michael Borgwardt Jan 16 '12 at 11:34
-
5@MichaelBorgwardt: The question of the OP doesn't even mention multi-threading. He just asks if there is a performance difference between Integer and AtomicInteger. AtomicInteger has not been created to have a faster Integer. It has been created to provide a thread-safe, lock-free, mutable Integer. If you don't need mutability and are not executing in a multi-threaded environment, the performance of both doesn't matter. You choose the most appropriate type: Integer. AtomicInteger should only be considered if you need mutability (and thread-safety). – JB Nizet Jan 16 '12 at 11:49
-
Not entirely true. You might want to use AtomicInteger for mutability without thread safety, when you need to change outer integers from within a lambda function, which can only access final variables. You can have a completely different discussion about side effects though. – andresp Nov 28 '19 at 18:13
AtomicInteger
allows some (not all!) operations that would otherwise require synchronization to be performed in a lock-free manner using special hardware instructions. How this affects performance is somewhat complex:
- First, it's a micro-optimization that will only matter if this particular operation is on your application's critical path.
- The special hardware instructions may not be available on non-mainstream platforms, in which case
AtomicInteger
will probably be implemented using synchronization. - The JVM can often optimize away locking overhead when there is no contention (e.g., a single threaded application). In that case, there's probably no difference.
- If there is low to moderate lock contention (i.e. multiple threads, but they mostly do other things than just accessing that integer), the lock-free algorithm performs better than synchronization.
- If there is very heavy lock contention (i.e. lots of threads that spend a lot of time trying to access that integer), synchronization may perform better because the lock-free algorithm is based on constantly retrying the operation when it fails due to a collision.

- 28,107
- 9
- 89
- 113

- 342,105
- 78
- 482
- 720
Well, if you use it in multithreaded environment, as a, e.g. counter, then you have to synchronize
access to the Integer
public final class Counter {
private long value = 0;
public synchronized long getValue() {
return value;
}
public synchronized long increment() {
return ++value;
}
}
While you can have much better performance with AtomicInteger without synchronization
public class NonblockingCounter {
private AtomicInteger value;
public int getValue() {
return value.get();
}
public int increment() {
return value.incrementAndGet();
}
}
Recommended reading http://cephas.net/blog/2006/09/06/atomicinteger/
EDIT use incrementAndGet

- 15,669
- 5
- 44
- 68
-
-
you mean [getAndIncrement](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html#getAndIncrement())? Well, good question sir, I guess I was too quick and lazy. – bpgergo Jan 16 '12 at 10:49
-
No, I mean incrementAndGet. getAndIncrement would be equivalent to return i++. But your first snippet returnn ++i; – JB Nizet Jan 16 '12 at 10:56
-
-
1Also, Brian Goetz on IBMWorks (new link) https://www.ibm.com/developerworks/library/j-jtp11234/index.html – ZiglioUK Jan 09 '19 at 10:42
Came across this posting today but wanted to share my results (Please no comments on code as I had to hand type the following classes as the system I ran this one on was not connected to the internet :)
Bottom line the output from the code below was as follows:
ATOMIC Results: Elapsed = 25257 ms, ExpectedValue = 50000, FinalValue = 50000, true PrImItIvE Results: Elapsed = 25257 ms, ExpectedValue = 50000, FinalValue = 48991, false
For my usage in my particular app I have chosen to use Atomic values for status numbers in a monitoring class. In case someone else wanted to view some hard results I opted to post this information.
Have a great day!
Classes:
I created a main class with a primitive long and an atomic long and accessor increment methods, an IncrementAtomicRunnable and an 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.");
}
}
and finally 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.");
}
}

- 445
- 1
- 7
- 17
Other than the very minor synchronization overhead, no.

- 412,405
- 93
- 575
- 722
-
-
2It uses CAS instructions. You will not find the word "synchronized" anywhere in the class. The whole point of the atomic classes is to avoid synchronization. – Sina Madani Jan 13 '20 at 19:48