2016-11-19 8 views
0

これは学校の割り当てですが、私は実際にこの問題を解決する必要があります。私の人生のために、nextValue()の2つの異なるバージョンが異なって振る舞う理由を理解できません.1つはスレッドセーフで、もう1つは違うのです。誰かが私に正しい方向へのポインタを少なくとも与えることはできますか?スレッドセーフなスレッドと非スレッドセーフなカウンタの実装

public class NumGenerator { 

    static final int MIN_VALUE = -256; 
    static final int MAX_VALUE = 255; 
    static final int INITIAL_VALUE = MIN_VALUE -1; 


    private final AtomicInteger counter = new AtomicInteger(INITIAL_VALUE); 
    private final AtomicInteger resetCounter = new AtomicInteger(0); 

    private final Object lock = new Object(); 

    // Thread safe 
    public int nextValue() { 
     int next = counter.incrementAndGet();  
     if (next > MAX_VALUE) {       
      synchronized (lock) {      
       next = counter.incrementAndGet(); 
       if (next> MAX_VALUE) {     
        counter.set(MIN_VALUE); 
        resetCounter.incrementAndGet(); 
        next = MIN_VALUE; 
       } 

      } 
     } 
     return next; 
    } 

    // Non thread safe 
    public int nextValue() { 
     int next = counter.incrementAndGet(); 
     if (next > MAX_VALUE) { 
      synchronized (lock) { 
       int i = counter.get(); 
       if (i > MAX_VALUE) { 
        counter.set(INITIAL_VALUE); 
        resetCounter.incrementAndGet(); 
       } 
       next = counter.incrementAndGet(); 
      } 
     } 
     return next; 
    } 
} 
+0

両方のコードのロジックが異なるようです。 IMHO、両方の関数はスレッドセーフです。しかし、前述のように、両方の関数が期待したものとは異なる出力を返すことがあります。 –

+0

あなたは正しいです、彼らは異なる出力を返します...しかし、なぜですか?私にとっては、彼らは機能的には同じように見えます。私は何が欠けていますか? – BadCash

+0

'counter.get();'と 'counter.incrementAndGet(); 'は違う。だからあなたは別の出力を得るでしょう – iNan

答えて

1

がのが値を言ってみましょう...私は下の同じクラスの両方のバージョンを用意しましたが、明らかに、彼らは両方のコードに存在していないよ:MIN_VALUE = -1、MAX_VALUE = 3 、カウンタ= 3

コード1:

synchronized (lock) {      
       next = counter.incrementAndGet(); 
       if (next> MAX_VALUE) {     
        counter.set(MIN_VALUE); 
        resetCounter.incrementAndGet(); 
        next = MIN_VALUE; 
       } 

      } 
  1. はインクリメントカウンタの値を計算し、それを比較に使用します。
  2. したがって、nextの値は4になります。if(next > MAX_VALUE)はif(4> 3)になります。これはnextの値を-1に変更して返します。

コード2:

synchronized (lock) { 
       int i = counter.get(); 
       if (i > MAX_VALUE) { 
        counter.set(INITIAL_VALUE); 
        resetCounter.incrementAndGet(); 
       } 
       next = counter.incrementAndGet(); 
      } 
  1. 次に比較対抗するために値を割り当てます。
  2. iの値は依然として3になります。if(i > MAX_VALUE)はif(3> 3)になりますが、出力として3を返しません。

incrementAndGetおよびgetが異なる。 同じ値を持つコードが異なる出力を返しています。 最初に値を増分してから条件をチェックし、もう1つは値を最初にチェックしてから操作を実行します。

if(variable> MAX_VALUE)内のコードでも出力が異なります。

これはスレッドの安全性とは関係ありません。

+0

私はちょうど違いが何かを考え出した。 'IncrementAndGet()'と 'get()'を使って違いがあるのは正しいですが、スレッドの安全性とは何の関係もないことに同意しません。両方のコードは単一のスレッドで動作しますが、同時に呼び出されると、最初の 'incrementAndGet()'と 'get()'の間で別のスレッドによって値が変更される可能性があります。最初のIF文と等しくなければなりません。基本的にコードでは、外側のIFが存在しないかのように、 'counter 'は2番目のIFで何でもできると仮定する必要があります。 – BadCash

+0

@BadCashこれは理想的ではないはずです。同期化されたブロックは両方のコードがスレッドセーフであることを保証する必要があります。そのため、 'incrementamentandGet()'と 'get()'の両方は効果がありません。ただ一つのスレッドにブロック内で実行する機会が与えられます。スレッドの安全性に着目すると、2つのスレッドが同時に値をインクリメントすると、同期ブロック 'int next = counter.incrementAndGet();'の外側に問題があり、nextのローカルコピーの値が異なります。だからこの行を考えると、コードはどちらもスレッドセーフではありません。 –

+0

はい、最初のバージョンには同じ 'next = incrementAndGet();があります。 (次のMAX_VALUE) 'を同期ブロック内に置いてスレッドセーフにします。私は、メソッド全体を 'synchronized'にして、ただ一つのIF文を持っているのと同じ効果があると思いますが、最初のIF文が偽であるすべてのケースについて他のスレッドのメソッドをブロックしないという利点があります... – BadCash

0

考えてみてください。どちらの方法もスレッドセーフです。どちらの方法でも同期されているためです。 synchronizedブロックはスレッドの安全性のために使用されます。

0

どちらもスレッドセーフです。おそらく、コードをテストする方法をコードに貼り付けることができます。問題はそこにあるかもしれません。

関連する問題