2016-03-20 18 views
1

私はJavaスレッドを騙しています。私はいくつかのスレッドを作成して実行する小さなプログラムを書いています。各スレッドでは、値が複数回インクリメントされます。 ThreadLocalクラスを使用して、リソースの競合がないようにしました。Javaの並行性:奇妙な出力

出典:

MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 

私が見に期待するものはどれ:

class MyValueHolder { 

    public static ThreadLocal<Integer> value = new ThreadLocal<Integer>() 
    { 
     protected Integer initialValue() { 
      return 0; 
     } 
    }; 

    public static void increment() { 
     value.set(value.get() + 1); 
    } 

    public static Integer get() { 
     return value.get(); 
    } 
} 

class MyTask implements Runnable { 

    public static int counter; 

    public MyTask() { 
     counter++; 
    } 

    public void run() { 

     for(int i = 0; i < 100; i++) { 
      MyValueHolder.increment(); 
     } 
     System.out.println("MyTask " + counter + ", Value " + MyValueHolder.get()); 
    } 
} 

public class Main { 

    public static void main(String[] args) { 

     ExecutorService es = Executors.newCachedThreadPool(); 

     for(int i = 0; i < 5; i++) { 

      es.execute(new MyTask()); 
     } 

     es.shutdownNow(); 
    } 
} 

終了後出力はこの時間のほとんどです。

はしかし、時々私はこのような何かを得る:

MyTask 2, Value 100 
MyTask 4, Value 200 
MyTask 5, Value 300 
MyTask 5, Value 100 
MyTask 5, Value 100 

さて、これは紛らわしいです。各タスクが全く同じことをしても、値が異なるのはなぜですか?

+0

スレッドが実行される順序は、開始された順序であることが保証されていません**。スレッドを特定の順序で実行する必要がある場合は、 'wait' /' notify'または['CountDownLatch'](https://docs.oracle.com/javase/7/docs/api/java/util/)を使用してください。同時/ CountDownLatch.html)。 – Majora320

答えて

5

すべてRunnableを追加する前に、Runnableが終了した場合、CachedThreadPoolExecutorはスレッドを再利用します。この場合、そのスレッドのThreadLocalも再利用されます。

0

出力が得られている間、スレッドは実行を継続します。スレッドが終了するのを待つ必要があります。isAlive();を試行できます。スレッドと一緒に

1

上記のように、ThreadLocalは再利用されています。

カウンタには、代わりにAtomicIntegerを使用し、初期値を設定します。 カウンタ++はアトミック操作ではなく、その2つの操作であり、スレッドセーフではありません。

+0

'counter 'はコンストラクタ内で値がインクリメントされ、コンストラクタがmainメソッドからのみ呼び出されるため、現在は問題ありません。 –

+0

申し訳ありませんが、明らかに正しいです。カウンターは、すべてのコンストラクターが呼び出される前にスレッドの実行メソッドが終了しているため、誤った数値を出力しています。 – LiozM