17

While using multiple threads I have learnt to use Static variables whenever I want to use a counter that will be accessed by multiple threads.

Example:

static int count=0; Then later in the program I use it as count++;.

Today I came across something called AtomicInteger and I also learned that it is Thread safe and could use one of its methods called getAndInrement() to achieve the same effect.

Could anyone help me to understand about using static atomicInteger versus static int count?

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
user547453
  • 1,035
  • 6
  • 22
  • 38

7 Answers7

25

- AtomicInteger is used to perform the atomic operation over an integer, its an alternative when you don't want to use synchronized keyword.

- Using a volatile on a Non-Atomic field will give inconsistent result.

int volatile count;

public void inc(){

count++

}

- static will make a variable shared by all the instances of that class, But still it will produce an inconsistent result in multi-threading environment.

So try these when you are in multithreading environment:

1. Its always better to follow the Brian's Rule:

When ever we write a variable which is next to be read by another thread, or when we are reading a variable which is written just by another thread, it needs to be synchronized. The shared fields must be made private, making the read and write methods/atomic statements synchronized.

2. Second option is using the Atomic Classes, like AtomicInteger, AtomicLong, AtomicReference, etc.

ajduke
  • 4,991
  • 7
  • 36
  • 56
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
9

I agree with @Kumar's answer.

Volatile is not sufficient - it has some implications for the memory order, but does not ensure atomicity of ++.

The really difficult thing about multi-threaded programming is that problems may not show up in any reasonable amount of testing. I wrote a program to demonstrate the issue, but it has threads that do nothing but increment counters. Even so, the counts are within about 1% of the right answer. In a real program, in which the threads have other work to do, there may be a very low probability of two threads doing the ++ close enough to simultaneously to show the problem. Multi-thread correctness cannot be tested in, it has to be designed in.

This program does the same counting task using a simple static int, a volatile int, and an AtomicInteger. Only the AtomicInteger consistently gets the right answer. A typical output on a multiprocessor with 4 dual-threaded cores is:

count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000

Here's the source code:

  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicInteger;

  public class Test {
    private static int COUNTS_PER_THREAD = 1000000;
    private static int THREADS = 2;

    private static int count = 0;
    private static volatile int volatileCount = 0;
    private static AtomicInteger atomicCount = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {
      List<Thread> threads = new ArrayList<Thread>(THREADS);
      for (int i = 0; i < THREADS; i++) {
        threads.add(new Thread(new Counter()));
      }
      for (Thread t : threads) {
        t.start();
      }
      for (Thread t : threads) {
        t.join();
      }
      System.out.println("count: " + count +  " volatileCount: " + volatileCount + " atomicCount: "
          + atomicCount + " Expected count: "
          + (THREADS * COUNTS_PER_THREAD));
    }

    private static class Counter implements Runnable {
      @Override
      public void run() {
        for (int i = 0; i < COUNTS_PER_THREAD; i++) {
          count++;
          volatileCount++;
          atomicCount.incrementAndGet();
        }
      }
    }
  }
Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • Thanks Patricia....I understand the use of atomicInteger when I have to use a counter as indicated in my original question. But what if I have 3 synchronized threads updating a variable's value like ThreadA, ThreadB and ThreadC (for example). In this case (as Kumar suggested), I have to use a private Synchronized method to read and write the value. And also make my variable defined as `Static Volatile`. Example: `private volatile static String threadName = "ThreadX";` – user547453 Nov 28 '12 at 07:34
  • 1
    @user547453 If all accesses to a variable are synchronized on the same object, there is no need to make it volatile. Doing so will either have no effect or slow down your code unnecessarily. There are many ways to make a variable shared between multiple threads - it does not have to be static. – Patricia Shanahan Nov 28 '12 at 10:36
  • 1
    One important thing to note here: `++` is not an atomic operation - it's a shorthand for `a = a + 1`, which consists of reading the value and writing the value. However reading or setting the value IS an atomic operation on a volatile field. – mucaho Apr 10 '16 at 17:51
2

With AtomicInteger the incrementAndGet() guaranteed to be atomic.
If you use count++ to get the previous value it is not guaranteed to be atomic.


Something the I missed from your question - and was stated by other answer - static has nothing to do with threading.

Itay Karo
  • 17,924
  • 4
  • 40
  • 58
  • what do you mean by `atomic` ? – user547453 Nov 28 '12 at 05:55
  • 1
    it means, for example, that if two threads are using, for example `prevCount = count++` on the same time, it might be that both of the thread will get the same value of prevCount. – Itay Karo Nov 28 '12 at 06:03
2

"static" make the var to be class level. That means, if you define "static int count" in a class, no matter how many instances you created of the class, all instances use same "count". While AtomicInteger is a normal class, it just add synchronization protection.

TieDad
  • 9,143
  • 5
  • 32
  • 58
1

static int counter would give you inconsistent result in multithreaded environment unless you make the counter volatile or make the increment block synchronized.

In case of automic it gives lock-free thread-safe programming on single variables.

More detail in automic's and link

Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103
1

I think there is no gurantee to see on count++ the newest value. count++ must read the value of count. Another Thread can have written a new value to count but stored it's value on the Thread local cache, i. e. does not flush to main memory. Also your Thread, that reads count, has no gurantee to read from the main memory, i. e. refresh from main memory. synchronize gurantees that.

Vertex
  • 2,682
  • 3
  • 29
  • 43
1

AtomicInteger is to make the get and increment as an atomic process. It can be thought as a Sequencer in Database. It provides utility methods to increment, decrement delta int values.

static int can cause issue if you are getting counter and then processing and then updating it. AtomicInteger does it easily but you can't use it if you have to update the counter based on processing results.

Pankaj
  • 5,132
  • 3
  • 28
  • 37