17

複数のスレッドを使用している間、複数のスレッドによってアクセスされるカウンターを使用したいときはいつでも静的変数を使用することを学びました。

例:

static int count=0;その後、プログラムの後半でそれをとして使用しcount++;ます。

今日、私はと呼ばれるものに出くわしました。AtomicIntegerまた、それがスレッドセーフでありgetAndInrement()、同じ効果を達成するために呼び出されるメソッドの1つを使用できることも学びました。

誰かが私がstatic atomicInteger対を使用することについて理解するのを手伝ってもらえstatic int countますか?

4

7 に答える 7

25

- 整数に対してアトミック操作AtomicIntegerを実行するために使用されます。キーワードを使用したくない場合の代替手段です。synchronized

-volatile非原子フィールドでを使用すると、一貫性のない結果が得られます。

int volatile count;

public void inc(){

count++

}

- staticそのクラスのすべてのインスタンスで変数を共有しますが、それでもマルチスレッド環境で一貫性のない結果が生成されます。

したがって、マルチスレッド環境にいるときにこれらを試してください。

1.ブライアンのルールに従う方が常に良いです:

次に別のスレッドによって読み取られる変数を書き込むとき、または別のスレッドだけによって書き込まれる変数を読み取るときは、同期する必要があります。共有フィールドをプライベートにして、読み取りメソッドと書き込みメソッド/アトミックステートメントを同期させる必要があります。

2. 2番目のオプションはAtomic Classes、のようなを使用することですAtomicInteger, AtomicLong, AtomicReference, etc.

于 2012-11-28T06:17:53.777 に答える
9

@Kumarの答えに同意します。

揮発性は十分ではありません-それはメモリの順序にいくつかの影響を及ぼしますが、++の原子性を保証しません。

マルチスレッドプログラミングで本当に難しいのは、妥当な量のテストでは問題が発生しない可能性があることです。この問題を実証するプログラムを作成しましたが、カウンターをインクリメントするだけのスレッドがあります。それでも、カウントは正解の約1%以内です。スレッドが他の作業を行う実際のプログラムでは、2つのスレッドが問題を示すのに十分に近い++を実行する可能性は非常に低い可能性があります。マルチスレッドの正確性はでテストできません。で設計する必要があります。

このプログラムは、単純なstatic 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();
        }
      }
    }
  }
于 2012-11-28T07:01:49.470 に答える
2

アトミックであることが保証されていますAtomicInteger。 以前の値を取得するために使用する場合、それがアトミックであるとは限りません。 incrementAndGet()
count++


私があなたの質問から見逃したこと-そして他の答えによって述べられた-静的はスレッド化とは何の関係もありません。

于 2012-11-28T05:54:34.617 に答える
2

「静的」は、変数をクラスレベルにします。つまり、クラスで「static int count」を定義すると、そのクラスで作成したインスタンスの数に関係なく、すべてのインスタンスが同じ「count」を使用します。AtomicIntegerは通常のクラスですが、同期保護を追加するだけです。

于 2012-11-28T05:59:41.853 に答える
1

static int countermultithreadedカウンターを作成するvolatileか、増分ブロックを作成しない限り、環境で一貫性のない結果が得られますsynchronized

automicそれの場合、lock-free thread-safe単一の変数でプログラミングを行います。

オートミックリンクの詳細

于 2012-11-28T06:01:05.190 に答える
1

count++最新の価値を見るための保証はないと思います。count++の値を読み取る必要がありますcount。別のThreadユーザーは、新しい値をローカルキャッシュに書き込んでも、countその値をローカルキャッシュに保存することができThreadます。つまり、メインメモリにフラッシュしません。また、Thread読み取りcountを行うyourには、メインメモリから読み取る保証がありません。つまり、メインメモリから更新する必要があります。synchronizeそれを保証します。

于 2012-11-28T06:08:43.157 に答える
1

AtomicIntegerは、アトミックプロセスとしてgetとincrementを作成します。これは、データベースのシーケンサーと考えることができます。deltaint値をインクリメントおよびデクリメントするユーティリティメソッドを提供します。

static intは、カウンターを取得してから処理してから更新する場合に問題を引き起こす可能性があります。AtomicIntegerは簡単に実行できますが、処理結果に基づいてカウンターを更新する必要がある場合は使用できません。

于 2012-11-28T06:08:54.520 に答える