2009-07-16 10 views
2

私は私が期待どおりに動作しない同期化の問題を抱えているが、私はまた、揮発性のキーワードを使用してみました:Javaの同期問題

共有オブジェクト:


public class ThreadValue { 
private String caller; 
private String value; 
public ThreadValue(String caller, String value) { 
    this.value = value; 
    this.caller = caller; 
} 

public synchronized String getValue() { 
    return this.caller + "  " + this.value; 
} 
public synchronized void setValue(String caller, String value) { 
    this.caller = caller; 
    this.value = value; 
} 
} 

スレッド1:


class CongoThread implements Runnable { 
    private ThreadValue v; 
    public CongoThread(ThreadValue v) { 
    this.v = v; 

    } 
    public void run() { 
    for (int i = 0; i 10; i++) { 
    v.setValue("congo", "cool"); 
    v.getValue(); 
    } 
    } 
} 

スレッド2:


class LibyaThread implements Runnable { 
    private ThreadValue v; 
    public LibyaThread(ThreadValue v) { 
    this.v = v; 

    } 
    public void run() { 
    for (int i = 0; i 10; i++) { 
     v.setValue("libya", "awesome"); 
     System.out.println("In Libya Thread " + v.getValue()); 

    } 
    } 
} 

クラスを呼び出す:


class TwoThreadsTest { 
    public static void main (String args[]) { 

    ThreadValue v = new ThreadValue("", ""); 
     Thread congo = new Thread(new CongoThread(v)); 
     Thread libya = new Thread(new LibyaThread(v)); 

    libya.start(); 
     congo.start(); 

    } 
} 

時折私が手決して起こらないはずです を「リビアスレッドコンゴクール」。私はただ期待しています: "リビアでスレッドlibya素晴らしい" "コンゴのスレッドコンゴで"

私はそれらが混在することを期待していません。

答えて

5

の呼び出しは次のようにインターリーブすることができます。

Thread 1 : v.setValue() 
Thread 2 : v.setValue() 
Thread 1 : v.getValue() // thread 1 sees thread 2's value 
Thread 2 : v.getValue() // thread 2 sees thread 2's value 
3

それは正しいですので、それがこの順で次のようになります。

v.setValue("libya", "awesome"); 
//context switch 
v.setValue("congo", "cool"); 
//context switch 
System.out.println("In Libya Thread " + v.getValue()); 

したがって、あなたは、いくつかの意味での競合状態を持っています。同期化は、同期メソッドを呼び出すときにロックを取得するため、変数への同期アクセスを暗示する別の方法が必要です。

public void run() 
{ 
    for (int i = 0; i 10; i++) 
    { 
    synchronized(v) 
    { 
     v.setValue("caller", "value"); 
     v.getValue(); 
    } 
    } 
} 
3

のgetValue()とのsetValue(への呼び出し)がインターリーブされることがあります。たとえば、次の方法から同期して行う削除することができます。

つまり、別のスレッドがgetValue()またはsetValue()と同時にgetValue()にスレッドを持たず、同じようにスレッドがsetValue()に存在せず、別のスレッドがgetValue()またはsetValue ()。

しかし、1つのスレッドが別のスレッドによって先取りされずにsetValue()getValue()を順次呼び出すという保証はありません。

基本的に、これは完全に合法と可能です:

スレッド1:v.setValue()
他のスレッド(S):v.getValue任意の数の()さん/ v.setValue ()さん
スレッド1:v.getValue()

4

これは、あなたが探している動作を取得する必要があります。

スレッド1:

class CongoThread implements Runnable { 
    private ThreadValue v; 

    public CongoThread(ThreadValue v) { 
     this.v = v; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized(v) { 
       v.setValue("congo", "cool"); 
       System.out.println("In Congo Thread " + v.getValue()); 
      } 
     } 
    } 
} 

スレッド2:非自明なプログラムで

class LibyaThread implements Runnable { 
    private ThreadValue v; 

    public LibyaThread(ThreadValue v) { 
     this.v = v; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized(v) { 
       v.setValue("libya", "awesome"); 
       System.out.println("In Libya Thread " + v.getValue()); 
      } 
     } 
    } 
} 
+1

、あなたはおそらく同期のも、このレベルを非表示にします。それ自体が同期するsetValueAndReturnString()のようなメソッドを持っています。マルチスレッドを正しく処理する呼び出し側に頼ることは望ましくありません。 – AngerClown

+0

合意。私は彼が求めていた振る舞いを達成するはずのコードバージョンをMoに提供することで、他のユーザーから提供されたレスポンスとともに、何が間違っているのか理解し、同期の仕組みを理解するのに役立ちます。 –