1

同期を実証する小さなプログラムを取得しようとしていますが、何らかの理由で期待を満たしていません。ポイントは、1000 個のスレッドを作成し、それらすべてに静的な Integer オブジェクトの「合計」に 1 を加算させることです。出力は 1000 になるはずですが、異なる出力が得られます。addSum() メソッドがまったく同期されていないようです。合計の出力が速すぎると考えて、println を遅らせようとしましたが、それは問題ではありません。ここで何が欠けていますか?

public class sumsync implements Runnable {
public static Integer sum = new Integer(0);
public sumsync(){
}

private synchronized void addSum(int i){
    sum += i;
}

@Override
public void run() {
    addSum(1);
}
}

メインクラス:

public class sumsyncinit {

private static final int max_threads = 1000;

public static void main(String[] args) {

sumsync task = new sumsync();
Thread thread;

    for(int i=0; i<max_threads;i++){
        thread = new Thread(task);
        thread.start();
    }
    System.out.println(sumsync.sum);
}

}
4

3 に答える 3

5

スレッドが終了するのを待っていないため、すべてのインクリメントが実行されたという保証はありません。addSum基本的に、一度に 1 つのスレッドのみがメソッド内にあることを保証しているだけです。Futuresを使用して結果を待つことができます。

于 2013-03-10T14:33:47.503 に答える
0

ThreadPoolExecutor( http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html )を使用して、毎回新しいスレッドを作成するのではなく、まずプーリングを行い、次に、awaitTermination結果を出力する前にすべてのスレッドの終了を待つためにそのメソッドを呼び出します。

実際、あなたの場合、すべてのスレッドが変数のインクリメントを終了した後に印刷が実行されるのを防ぐメカニズムを設定していません。そのため、印刷結果がランダムになる場合があります。 awaitTerminationすべてのスレッドでとして機能し、join()この要件を達成します。

さらに、この場合、変数を作成するvolatileことは役に立たず、安全ではありません。

実際、synchronizedキーワードはすでにメモリバリアと原子性として機能していますが、揮発性は単にメモリバリアを保証するだけです。

さらに、変数を作成したい場合に留意すべきルールは次のvolatileとおりです。

ロックの代わりに volatile 変数を使用できるのは、限られた状況でのみです。volatile 変数が目的のスレッド セーフを実現するには、次の両方の基準を満たす必要があります。 変数へ
の書き込みは、その現在の値に依存しません。
変数は、他の変数との不変条件には参加しません。

于 2013-03-10T14:38:07.950 に答える
-2

を作ることもできsumますAtomicInteger

するとaddSum()以下のようになります。

public static AtomicInteger sum = new AtomicInteger(0);

private void addSum(int i){
    sum.addAndGet(i);
}

更新:上記の解決策は、競合状態のみに対処することを目的としていました。以下のスティーブンのコメントの後、メインスレッドが他のスレッドが完了するのを待ってから最終値を出力するように、完全なソリューションを投稿しています。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class sumsync implements Runnable {
public static AtomicInteger sum = new AtomicInteger(0);
private CountDownLatch latch;
public sumsync(CountDownLatch latch){

  this.latch = latch;
}

private synchronized void addSum(int i){
    sum.addAndGet(i);
}

@Override
public void run() {
    addSum(1);
    latch.countDown();
}
}

import java.util.concurrent.CountDownLatch;

public class sumsyncinit {

private static final int max_threads = 1000;

public static void main(String[] args) {

CountDownLatch latch = new CountDownLatch(max_threads);

sumsync task = new sumsync(latch);
Thread thread;

    for(int i=0; i<max_threads;i++){
        thread = new Thread(task);
        thread.start();
    }
    try {
      latch.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(sumsync.sum);
}

}
于 2013-03-10T14:39:37.383 に答える