When is AtomicInteger preferable to synchronization?


ef2011:

Why would I use an AtomicInteger since AtomicIntegerit's at least an order of magnitude slower than the intprotected object ?synchronized

For example, if I just want to increment a value in a intthread-safe way , why not always use:

synchronized(threadsafeint) {
  threadsafeint++;
}

instead of using the much slower AtomicInteger.incrementAndGet() ?

Peter Lowry:

Since AtomicInteger is at least an order of magnitude slower than a sync-protected int, why would I use AtomicInteger?

AtomicInteger is faster.

static final Object LOCK1 = new Object();
static final Object LOCK2 = new Object();
static int i1 = 0;
static int i2 = 0;
static final AtomicInteger ai1 = new AtomicInteger();
static final AtomicInteger ai2 = new AtomicInteger();

public static void main(String... args) throws IOException {
    for(int i=0;i<5;i++) {
        testSyncInt();
        testAtomicInt();
    }
}

private static void testSyncInt() {
    long start = System.nanoTime();
    int runs = 10000000;
    for(int i=0;i< runs;i+=2) {
        synchronized (LOCK1) {
            i1++;
        }
        synchronized (LOCK2) {
            i2++;
        }
    }
    long time = System.nanoTime() - start;
    System.out.printf("sync + incr: Each increment took an average of %.1f ns%n", (double) time/runs);
}

private static void testAtomicInt() {
    long start = System.nanoTime();
    int runs = 10000000;
    for(int i=0;i< runs;i+=2) {
        ai1.incrementAndGet();
        ai2.incrementAndGet();
    }
    long time = System.nanoTime() - start;
    System.out.printf("incrementAndGet: Each increment took an average of %.1f ns%n", (double) time/runs);
}

print

sync + incr: Each increment took an average of 32.4 ns
incrementAndGet: Each increment took an average of 20.6 ns
sync + incr: Each increment took an average of 31.4 ns
incrementAndGet: Each increment took an average of 12.9 ns
sync + incr: Each increment took an average of 29.6 ns
incrementAndGet: Each increment took an average of 12.9 ns
sync + incr: Each increment took an average of 35.1 ns
incrementAndGet: Each increment took an average of 16.6 ns
sync + incr: Each increment took an average of 29.9 ns
incrementAndGet: Each increment took an average of 13.0 ns

Add some contention as suggested by @assylias. It shows that the CPU can optimize access when you are only really using one thread.

static final Object LOCK1 = new Object();
static final Object LOCK2 = new Object();
static int i1 = 0;
static int i2 = 0;
static final AtomicInteger ai1 = new AtomicInteger();
static final AtomicInteger ai2 = new AtomicInteger();

public static void main(String... args) throws  ExecutionException, InterruptedException {
    for(int i=0;i<5;i++) {
        testSyncInt();
        testAtomicInt();
    }
}

private static void testSyncInt() throws ExecutionException, InterruptedException {
    long start = System.nanoTime();
    final int runs = 1000000;
    ExecutorService es = Executors.newFixedThreadPool(2);
    List<Future<Void>> futures = new ArrayList<>();
    for(int t=0;t<8;t++) {
        futures.add(es.submit(new Callable<Void>() {
            public Void call() throws Exception {
                for (int i = 0; i < runs; i += 2) {
                    synchronized (LOCK1) {
                        i1++;
                    }
                    synchronized (LOCK2) {
                        i2++;
                    }
                }
                return null;
            }
        }));
    }
    for (Future<Void> future : futures) {
        future.get();
    }
    es.shutdown();
    long time = System.nanoTime() - start;
    System.out.printf("sync + incr: Each increment took an average of %.1f ns%n", (double) time/runs/2);
}

private static void testAtomicInt() throws ExecutionException, InterruptedException {
    long start = System.nanoTime();
    final int runs = 1000000;
    ExecutorService es = Executors.newFixedThreadPool(2);
    List<Future<Void>> futures = new ArrayList<>();
    for(int t=0;t<8;t++) {
        futures.add(es.submit(new Callable<Void>() {
            public Void call() throws Exception {
                for (int i = 0; i < runs; i += 2) {
                    ai1.incrementAndGet();
                    ai2.incrementAndGet();
                }
                return null;
            }
        }));
    }
    for (Future<Void> future : futures) {
        future.get();
    }
    es.shutdown();
    long time = System.nanoTime() - start;
    System.out.printf("incrementAndGet: Each increment took an average of %.1f ns%n", (double) time/runs/2);
}

print

sync + incr: Each increment took an average of 478.6 ns
incrementAndGet: Each increment took an average of 191.5 ns
sync + incr: Each increment took an average of 437.5 ns
incrementAndGet: Each increment took an average of 169.8 ns
sync + incr: Each increment took an average of 408.1 ns
incrementAndGet: Each increment took an average of 180.8 ns
sync + incr: Each increment took an average of 511.5 ns
incrementAndGet: Each increment took an average of 313.4 ns
sync + incr: Each increment took an average of 441.6 ns
incrementAndGet: Each increment took an average of 219.7 ns

Related


When is AtomicInteger preferable to synchronization?

ef2011: Why would I use an AtomicInteger since AtomicIntegerit's at least an order of magnitude slower than the intprotected object ?synchronized For example, if I just want to increment a value in a intthread-safe way , why not always use: synchronized(thread

When is AtomicInteger preferable to synchronization?

ef2011: Why would I use an AtomicInteger since AtomicIntegerit's at least an order of magnitude slower than the intprotected object ?synchronized For example, if I just want to increment a value in a intthread-safe way , why not always use: synchronized(thread

Does AtomicInteger handle synchronization?

Ana Maria: If both threads are incrementing the same int iusing i++ , there may be a problem because i++ is not an atomic operation. That's why it exists , which makes atomic increments. So if we have 1 core and 2 threads doing it , there is absolutely no prob

Does AtomicInteger handle synchronization?

Ana Maria: If both threads are incrementing the same int iusing i++ , there may be a problem because i++ is not an atomic operation. That's why it exists , which makes atomic increments. So if we have 1 core and 2 threads doing it , there is absolutely no prob

Does AtomicInteger handle synchronization?

Ana Maria: If both threads are incrementing the same int iusing i++ , there may be a problem because i++ is not an atomic operation. That's why it exists , which makes atomic increments. So if we have 1 core and 2 threads doing it , there is absolutely no prob

When immutable collections are preferable

born Recently read about immutable collections. When performing reads more frequently than writes, it is recommended to use them as threads for safe reads. Then, I want to test the reading performance of ImmutableDictionary vs ConcurrentDictionary. Here is a v

When immutable collections are preferable

born Recently read about immutable collections. When performing reads more frequently than writes, it is recommended to use them as threads for safe reads. Then, I want to test the reading performance of ImmutableDictionary vs ConcurrentDictionary. Here is a v

When immutable collections are preferable

born Recently read about immutable collections. When performing reads more frequently than writes, it is recommended to use them as threads for safe reads. Then, I want to test the reading performance of ImmutableDictionary vs ConcurrentDictionary. Here is a v

When immutable collections are preferable

not Recently read about immutable collections. When performing reads more frequently than writes, it is recommended to use them as threads for safe reads. Then, I want to test the reading performance of ImmutableDictionary vs ConcurrentDictionary. Here is a ve

When is DownloadManager preferable over HttpUrlConnection?

Matt Logan I'm requesting plain text data from a Web API, which could be as large as ~5 MB or as small as ~1 KB. I was hesitant HttpUrlConnectionbecause the possibility of timeouts increased and the memory was taking 5 MB InputStream. From the Android document

When is DownloadManager preferable over HttpUrlConnection?

Matt Logan I'm requesting plain text data from a Web API, which could be as large as ~5 MB or as small as ~1 KB. I was hesitant HttpUrlConnectionbecause the possibility of timeouts increased and the memory was taking 5 MB InputStream. From the Android document

why! Preferable when checking if an object is true?

Giannis Some JavaScript examples for !!checking if an object is available // Check to see if Web Workers are supported if (!!window.Worker) { // Yes, I can delegate the boring stuff! } Why is it biased towards justice, if (window,Worker)and under what circu

why! Preferable when checking if an object is true?

Giannis Some JavaScript examples for !!checking if an object is available // Check to see if Web Workers are supported if (!!window.Worker) { // Yes, I can delegate the boring stuff! } Why is it biased towards justice, if (window,Worker)and under what circu

With ConcurrentHashMap, when is synchronization required?

For each position: I have a ConcurrentHashMap where I do the following: sequences = new ConcurrentHashMap<Class<?>, AtomicLong>(); if(!sequences.containsKey(table)) { synchronized (sequences) { if(!sequences.containsKey(table)) initial

With ConcurrentHashMap, when is synchronization required?

For each position: I have a ConcurrentHashMap where I do the following: sequences = new ConcurrentHashMap<Class<?>, AtomicLong>(); if(!sequences.containsKey(table)) { synchronized (sequences) { if(!sequences.containsKey(table)) initial

When to use synchronization in Java

User 5243421: I hope this will be enough information, so here it goes. If you need more information, find out in the comments. I have a class with two inner classes. The inner classes each have two methods to call methods in the outer class. So it looks like t

With ConcurrentHashMap, when is synchronization required?

For each position: I have a ConcurrentHashMap where I do the following: sequences = new ConcurrentHashMap<Class<?>, AtomicLong>(); if(!sequences.containsKey(table)) { synchronized (sequences) { if(!sequences.containsKey(table)) initial

When to use synchronization in Java

User 5243421: I hope this will be enough information, so here it goes. If you need more information, find out in the comments. I have a class with two inner classes. The inner classes each have two methods to call methods in the outer class. So it looks like t