3

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

3 に答える 3

4

なぜそれらは混合されないのでしょうか? 個々の呼び出しは同期されていますが、1 つのスレッドが v.setValue を呼び出し、次に別のスレッドが setValue を呼び出し、次に最初のスレッドが getValue() を呼び出すことを止めるものは何もありません。私はそれが起こっていると信じています。次を使用してこれを回避できます。

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

そうすれば、各反復で、その間に別のスレッドが呼び出されることなく、確実に呼び出さsetValue れます。 getValuesetValue

確かに、これは理想的な設計ではありませんが、このデモンストレーションは何よりも同期を理解するためのものだと思います :)

于 2009-07-16T13:15:13.460 に答える
2

何が起こるかは次のとおりです。

  1. スレッド 1 が値を設定します
  2. スレッド 2 は値を設定します
  3. スレッド 1 は、スレッド 2 によって設定された値を読み取ります。

これを修正するには、両方のスレッドの get/set 関数呼び出しを保護する 1 つのロック オブジェクトが必要です。これを行う最善の方法は、セットと取得の両方を行う追加の同期メソッドを作成することです。ただし、それが望ましくない場合もあります。その場合、両方のスレッドにロック オブジェクトを与えます。これは単なるオブジェクトです。次に、同期ブロックで使用します。

各スレッドの実装は次のようになります。正確に同じオブジェクトが必要であることに注意してください。

Object lockObject = new Object();
Thread t1 = new CongroThread(v, lockObject);
Thread t2 = new LibyaThread(v, lockObject);

...

class CongoThread implements Runnable {
    private ThreadValue v;
    private Object lockObject;

    public CongoThread(ThreadValue v, Object lockObject) {
    this.v = v;
    this.lockObject = lockObject,
    }
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized(lockObject)
            {
                v.setValue( "libya", "awesome" );
                System.out.println("In Libya Thread " + v.getValue() );
            }
        }
    }
}
于 2009-07-16T13:17:36.267 に答える
0

問題は、リビア スレッドの v.getValue() が、コンゴ スレッドが v.setValue() を呼び出した直後に呼び出されている可能性があるため、混乱が生じる可能性があることです。

解決策は、get 値と set 値の両方をスレッドでブロックすることです。そうしないと、引き続きその問題が発生します。セッター内でゲッターを呼び出すか、待機/通知を使用して、一方のスレッドが値を設定して取得するまで、もう一方のスレッドを待機させる必要があります。

于 2009-07-16T13:14:17.503 に答える