【问题标题】:Java - using AtomicInteger vs Static intJava - 使用 AtomicInteger 与静态 int
【发布时间】:2012-11-28 05:52:34
【问题描述】:

在使用多线程时,我学会了使用静态变量,只要我想使用将被多线程访问的计数器。

例子:

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

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

谁能帮助我了解使用static atomicIntegerstatic int count 的区别?

【问题讨论】:

  • 您必须自己保护对int 的并发访问。但是,AtomicInteger 被设计为线程安全的。
  • static 与多线程无关。
  • 据我了解,我们在多线程环境中使用 volatile 变量而不是静态变量。

标签: java atomic


【解决方案1】:

我同意@Kumar 的回答。

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

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

此程序使用简单的静态整数、易失整数和 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();
        }
      }
    }
  }

【讨论】:

  • 谢谢帕特里夏....当我必须使用原始问题中指出的计数器时,我了解 atomicInteger 的使用。但是,如果我有 3 个同步线程更新变量的值,例如 ThreadA、ThreadB 和 ThreadC(例如),该怎么办。在这种情况下(正如 Kumar 建议的那样),我必须使用私有 Synchronized 方法来读取和写入值。并将我的变量定义为Static Volatile。示例:private volatile static String threadName = "ThreadX";
  • @user547453 如果对变量的所有访问都在同一个对象上同步,则无需使其易失。这样做要么没有效果,要么会不必要地减慢你的代码。有很多方法可以在多个线程之间共享一个变量——它不必是静态的。
  • 这里需要注意的重要一点:++ 不是原子操作 - 它是 a = a + 1 的简写,包括读取值和写入值。但是,读取或设置值是对 volatile 字段的原子操作。
【解决方案2】:

- AtomicInteger 用于对整数执行原子操作,当您不想使用 synchronized 关键字时,它是一种替代方法。 p>

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

int volatile count;

public void inc(){

count++

}

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

所以在多线程环境中试试这些:

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

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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


      我从你的问题中遗漏了一些东西 - 并且由其他答案说明 - 静态与线程无关。

      【讨论】:

      • atomic 是什么意思?
      • 这意味着,例如,如果两个线程同时使用,例如prevCount = count++,则可能两个线程将获得相同的 prevCount 值。
      【解决方案5】:

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

      如果是automic,它会给出lock-free thread-safe 对单个变量的编程。

      automic'slink 中的更多详细信息

      【讨论】:

      • 我认为 volatile 不足以使 ++ 安全。
      【解决方案6】:

      我认为count++ 上的最新值无法保证。 count++ 必须读取 count 的值。另一个Thread 可以将新值写入count,但将其值存储在Thread 本地缓存中,即。 e.不会刷新到主内存。此外,您的Thread(读取为count)没有保证可以从主存储器读取,即。 e.从主存刷新。 synchronize 保证。

      【讨论】:

        【解决方案7】:

        AtomicInteger 就是让get和increment成为一个原子过程。它可以被认为是数据库中的排序器。它提供了增加、减少 delta int 值的实用方法。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-04
          相关资源
          最近更新 更多