2

Synchronized が期待どおりに動作しないという問題があります。volatile キーワードも使用してみました。

共有オブジェクト:


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();

    }
}

時折、絶対に起こらないはずの「In Libya Thread congo cool」が表示されます。私が期待するのは、「リビアでスレッド リビア 素晴らしい」「コンゴ スレッドでコンゴ クール」だけです。

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

4

4 に答える 4

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
于 2009-07-16T05:47:30.947 に答える
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() );
            }
        }
    }
}
于 2009-07-16T05:57:19.303 に答える
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();
   }
  }
}
于 2009-07-16T05:50:14.090 に答える
3

getValue() と setValue() の呼び出しはインターリーブされる場合があります。

つまり、別のスレッドが getValue() または setValue() にあると同時に getValue() にあるスレッドはなく、同様に別のスレッドが getValue() または setValue() にあるときに setValue() にあるスレッドもありません。

ただし、単一のスレッドが、別のスレッドによってプリエンプトされることなく、setValue() getValue() を順次呼び出すという保証はありません。

基本的に、これは完全に合法であり、可能です。

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

于 2009-07-16T05:50:54.277 に答える