2017-12-17 6 views
2

私はメソッドを同期させるが、そのオブジェクトレベルのロックを行うと、以下のコードが競合状態を引き起こす理由を説明することができます。 私はクラスレベルを使用する場合は間違いなく動作するので、私はスレッドによって占有されているロックがそれぞれ異なるのではないかと説明してください。Java Concurrencyの同期の問題

/** 
* 
*/ 
package lession2.shared.object; 

/** 
* @author so_what 
* 
*/ 

class SharedClass { 
    private static int sharedData; 

    public synchronized int getSharedData() { 
     return sharedData; 
    } 

    public synchronized void setSharedData(int sharedData) { 

     SharedClass.sharedData = sharedData; 
    } 

} 

//output of the program should be the distinct numbers 
public class StaleDataExample extends Thread { 
    static SharedClass s1=new SharedClass(); 
    static int counter=0; 
    public static void main(String args[]) throws InterruptedException { 

     StaleDataExample t1=new StaleDataExample(); 
     StaleDataExample t2=new StaleDataExample(); 
     StaleDataExample t3=new StaleDataExample(); 
     StaleDataExample t4=new StaleDataExample(); 
     StaleDataExample t5=new StaleDataExample(); 
     StaleDataExample t6=new StaleDataExample(); 
     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

     t5.start(); 
     t6.start(); 
     t1.join(); 
     t2.join(); 
     t3.join(); 
     t4.join(); 
     t5.join(); 
     t6.join(); 
     System.out.println(); 

    } 
    public void run() 
    { 

     s1.setSharedData(s1.getSharedData()+1); //read->modify->write operation 
     System.out.print(s1.getSharedData()+" "); 
    } 

} 
+2

'//読み取りを>変更 - >書き込み操作(write-operation)」のみが、「読み出し」と「書き込み」のみが(独立して)同期される。単一のアトミック操作である必要があります。 – tkausl

+0

getとset操作が同じロックを取得していない理由を正当化してください。同じロック複合アトミック性を取得しているためです。 –

+0

同じロックを取得しています。なぜなら、他のスレッドが介入することができる、全く同期していない値を変更するタイムスライスが存在するからです。 – tkausl

答えて

2

ここでの問題は、共有値をアトミック(同期など)の方法で増やしていないことです。

のは、次の行調べてみましょう:

s1.setSharedData(s1.getSharedData()+1) 

まず、あなたは、新しい値を設定するためのsynchronized. You then increment the value, at call setSharedData`である、getSharedDataを呼び出します。問題は、プログラムがgetとsetの間でコンテキスト切り替えを行う可能性があることです。

  1. スレッド#1通話getSharedData()、および0
  2. スレッド#2のコールgetSharedData()取得し、また0
  3. スレッド#1は、その値に1を加算し、setSharedData(1)を呼び出して取得します。次の例を考えてみましょう。
  4. スレッド#2もその値に1を加え、setSharedData(2)の代わりにsetSharedData(1)を呼び出します。このような問題を解決する

一つの方法は、クラスのユーザーが直接値を設定しますが、アトミック値インクリメントする方法とそれらを提供できるようにすることではありません。

class SharedClass { 
    private static int sharedData; 

    public synchronized int getSharedData() { 
     return sharedData; 
    } 

    public synchronized void incrementSharedData(int amount) { 
     sharedData += amount; 
    } 
} 
+0

ohh私は他の解決策がAtomicIntegerを使用してここで競合状態を防ぐことを忘れています。 また、同期メソッドでも計算が実行されます。 クラスSharedClass { \tプライベートのAtomicInteger sharedData =新規のAtomicInteger(0)。 \t public synchronized int getSharedData(){ \t \t return sharedData.getAndIncrement(); \t} \t} \t公共ボイドラン() \t {\t \t \t System.out.print(s1.getSharedData()+」「)。 \t} } –