Java - 使用AtomicInteger和Static int

时间:2012-11-28 05:52:34

标签: java atomic

在使用多个线程时,每当我想使用一个可被多个线程访问的计数器时,我就学会了使用静态变量。

示例:

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

今天我遇到了一个名为AtomicInteger的东西,我也了解到它是线程安全的,可以使用一个名为getAndInrement()的方法来达到同样的效果。

有人可以帮我理解使用static atomicIntegerstatic int count的对比吗?

7 个答案:

答案 0 :(得分:25)

- AtomicInteger用于对整数执行原子操作,当您不想使用{{1}时,它是另一种选择关键字。

- 在非原子字段上使用synchronized会产生不一致的结果。

volatile

- int volatile count; public void inc(){ count++ } 会使该类的所有实例共享一个变量,但仍然会在多个实体中产生不一致的结果线程环境。

在多线程环境中尝试这些:

1。遵循Brian的规则总是更好:

  

当我们编写一个接下来要被另一个读取的变量时   线程,或者当我们读取一个仅由其编写的变量时   另一个线程,它需要同步。共享字段必须是   私有化,制作读写方法/原子语句   同步。

2。第二个选项正在使用static,例如Atomic Classes

答案 1 :(得分:8)

我同意@ Kumar的回答。

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

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

该程序使用简单的静态int,volatile 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();
        }
      }
    }
  }

答案 2 :(得分:2)

AtomicInteger incrementAndGet()保证原子。{ 如果使用count++来获取先前的值,则不能保证它是原子的。


我错过了你的问题 - 并且通过其他答案说明 - 静态与线程无关。

答案 3 :(得分:1)

“static”使var成为类级别。这意味着,如果在类中定义“static int count”,无论您创建了多少个类实例,所有实例都使用相同的“count”。虽然AtomicInteger是普通类,但它只是添加了同步保护。

答案 4 :(得分:1)

static int counter会在multithreaded环境中为您提供不一致的结果,除非您使计数器volatile或增量块synchronized

如果是automic,则会对单个变量进行lock-free thread-safe编程。

automic'slink

中的详细信息

答案 5 :(得分:1)

我认为没有保证可以在count++上看到最新的价值。 count++必须读取count的值。另一个Thread可以为count写入一个新值,但将其值存储在Thread本地缓存中,i。即不会刷新到主存储器。另外,你的Thread读取count,没有保证从主存中读取,i。即从主内存刷新。 synchronize保证这一点。

答案 6 :(得分:1)

AtomicInteger将get和increment作为原子进程。它可以被认为是数据库中的序列发生器。它提供了实用程序方法来递增,递减delta int值。

如果你得到计数器然后处理然后更新它,

static int会导致问题。 AtomicInteger可以轻松完成,但如果您必须根据处理结果更新计数器,则无法使用它。