Is a static counter thread safe in multithreaded application?

后端 未结 6 763
青春惊慌失措
青春惊慌失措 2021-01-14 13:02
public class counting
{
  private static int counter = 0;

  public void boolean counterCheck(){
  counter++;
  if(counter==10)
  counter=0;
  }
}

6条回答
  •  半阙折子戏
    2021-01-14 13:48

    Imagine counter is 9.

    Thread 1 does this:

    counter++; // counter = 10
    

    Thread 2 does this:

    counter++; // counter = 11
    if(counter==10) // oops
    

    Now, you might think you can fix this with:

    if(counter >= 10) counter -= 10;
    

    But now, what happens if both threads check the condition and find that it's true, then both threads decrement counter by 10 (now your counter is negative).

    Or at an even lower level, counter++ is actually three operations:

    • Get counter
    • Add one to counter
    • Store counter

    So:

    1. Thread 1 gets counter
    2. Thread 2 gets counter
    3. Both threads add one to their counter
    4. Both threads store their counter

    In this situation, you wanted counter to be incremented twice, but it only gets incremented once. You could imagine it as if this code was being executed:

    c1 = counter;
    c2 = counter;
    c1 = c1 + 1;
    c2 = c2 + 1;
    counter = c1; // Note that this has no effect since the next statement overrides it
    counter = c2;
    

    So, you could wrap it in a synchronized block, but using an AtomicInteger would be better if you only have a few threads:

    public class counting {
        private static AtomicInteger counter = new AtomicInteger(0);
    
        public static void counterCheck() {
            int value = counter.incrementAndGet();
            // Note: This could loop for a very long time if there's a lot of threads
            while(value >= 10 && !counter.compareAndSet(value, value - 10)) {
                value = counter.get();
            }
        }
    }
    

提交回复
热议问题