Java - 使用 AtomicInteger vs Static int

2022-09-02 23:40:15

在使用多个线程时,我已经学会了每当我想使用将由多个线程访问的计数器时使用静态变量。

例:

static int count=0;然后稍后在程序中,我将其用作.count++;

今天,我遇到了一种叫做的东西,我还了解到它是线程安全的,可以使用它的一种调用方法来达到相同的效果。AtomicIntegergetAndInrement()

任何人都可以帮助我了解使用versus ?static atomicIntegerstatic int count


答案 1

- AtomicInteger用于对整数执行原子运算,当您不想使用关键字时,它是另一种选择。synchronized

-在非原子场上使用 a 将产生不一致的结果。volatile

int volatile count;

public void inc(){

count++

}

- static将使变量由该类的所有实例共享,但它仍然会在多线程环境中产生不一致的结果。

因此,当您处于多线程环境中时,请尝试以下操作:

1.遵循布莱恩规则总是更好:

每当我们编写一个接下来要由另一个线程读取的变量时,或者当我们读取仅由另一个线程写入的变量时,它需要同步。共享字段必须设为私有,以使读取和写入方法/原子语句同步。

2. 第二个选项是使用 ,如Atomic ClassesAtomicInteger, AtomicLong, AtomicReference, etc.


答案 2

我同意@Kumar的答案。

易失性是不够的 - 它对内存顺序有一些影响,但不能确保++的原子性。

关于多线程编程的真正困难之处在于,问题可能不会出现在任何合理的测试量中。我写了一个程序来演示这个问题,但它的线程除了递增计数器之外什么都不做。即便如此,计数仍在正确答案的1%以内。在线程有其他工作要做的实际程序中,两个线程执行 ++ 的可能性可能非常低,足以同时显示问题。多线程的正确性不能被测试,它必须被设计进去。

该程序使用简单的静态int,易失性int和AtomicInteger执行相同的计数任务。只有 AtomicInteger 才能始终如一地获得正确的答案。具有 4 个双线程内核的多处理器上的典型输出为:

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

下面是源代码:

  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();
        }
      }
    }
  }

推荐