web-dev-qa-db-ja.com

静的変数のスレッドセーフ

_class ABC implements Runnable {
    private static int a;
    private static int b;
    public void run() {
    }
}
_

上記のJavaクラスがあります。このクラスのスレッドが複数あります。run()メソッドでは、変数abはそれぞれ数回インクリメントされます。インクリメントごとに、これらの変数をハッシュテーブルに配置します。

したがって、各スレッドは両方の変数をインクリメントし、それらをハッシュテーブルに配置します。これらの操作をスレッドセーフにするにはどうすればよいですか?

14

AtomicInteger を使用します。これは、スレッドセーフになるように設計されており、非常に使いやすく、アプリケーションに最小限の同期オーバーヘッドを与えます。

class ABC implements Runnable {
    private static AtomicInteger a;
    private static AtomicInteger b;
    public void run() {
        // effectively a++, but no need for explicit synchronization!
        a.incrementAndGet(); 
    }
}

// In some other thread:

int i = ABC.a.intValue(); // thread-safe without explicit synchronization
10
Bohemian

synchronizedメソッドを使用します。例:.

public synchronized void increment()
{
  a++; b++;
  // Push in to hash table.
}

上記は、単一のインスタンスを介して静的にアクセスしている場合に適していますが、複数のインスタンスがある場合は、(テストされていない)などの静的オブジェクトで同期する必要があります。

private static Object lock = new Object();

メソッドで

public void increment()
{
  synchronize(lock)
  {
    a++;b++;
    // do stuff
  }
}

注:これらのアプローチは、abを1つのアトミックアクションでインクリメントすることを前提としています。他の回答は、それらがどのようにできるかを強調しています個別に =アトミックを使用してインクリメント。

6
Nim

この質問への回答について、いくつか詳細を追加したいと思います。

まず、OPは次のことについて質問しています。

これらの操作をスレッドセーフにするにはどうすればよいですか?

この質問に答える前に、スレッドセーフとは何かについて一貫性を保つ必要があります。私が最も気に入っている定義は、「Java ConcurrencyInPractice」からのものです。

クラスは、ランタイム環境によるそれらのスレッドの実行のスケジューリングまたはインターリーブに関係なく、複数のスレッドからアクセスされたときに正しく動作し、呼び出し元のコードの側で追加の同期やその他の調整がない場合、スレッドセーフです。

定義に同意する場合は、さらに議論する前に一貫性に到達することを意味します。意図した操作に戻りましょう。それはa++b++です。インクリメント後、それらをHashTableに入れます。

a++操作の場合、これは実際には単一の操作ではありません。 リードモディファイライトのモデルに従います。ご覧のとおり、実際には3つの個別のステップが含まれています。値を読み取り、値を追加して保存し直します。 2つのスレッドがある場合は、変更と保存操作の後で、変数aと値1を同時に読み取ります。値は2になりますが、実際には3である必要があります。この状況が発生しないようにするには、他の人が提案しているように、AtomicIntegerタイプの代わりにintを直接使用できます。 AtomicIntegerは、アトミックに実行するインクリメントなどのいくつかの操作を保証します。つまり、read modify write操作を分割することはできず、1つの個別のステップとして実行されます。
その後、OPは値をHashTableに保存したいと考えています。 HashTableはスレッドセーフなコンテナーであり、他の同期は必要ありません。
この説明が他の方法で誰かを助けることができることを願っています。ありがとう。

2
Gearon