1

私は 2 つのスレッドを使用する Android アプリケーションで作業しています。最初の (ライター) スレッドは 2 つの変数を更新し、2 番目の (リーダー) スレッドは計算で両方を使用します。
2 番目のスレッドが正しい値を受け取るようにするにはどうすればよいですか?
これは私の最初の Java ロックの問題です。同期、揮発性、トライロックについて読んでいますが、まだ不明です。1 つの変数の場合、これは「簡単」ですが、2 つの変数に対してこれを行う方法がわかりません。

詳細:
変数は共有パブリック クラスにあります。 AppState extends Application:

public long appstate.writerVar1;
public int appstate.writerVar2;

メイン アクティビティでは、スレッドが作成され、appstate がスレッドに渡されます。

writerThread.appstate = appstate;
...
readerThread.appstate = appstate;

変数は、次のように writerThread と readerThread の両方からアクセスできます。

ライタースレッド、例:

appstate.writerVar1 = 1234;
appstate.writerVar2 = 5678;

リーダースレッド、例:

if( (appstate.writerVar1 == 9) && (appstate.writerVar2 == 6) ){

次のように動作するはずです:

writerThread:
- 両方の変数をロックする
- 両方を新しい値で更新する
- ロックを解除する

readerThread:
- 両方の変数をロックする
- 値を読み取る- ロックを
解除

する ありがとう!

--- 2012 年 4 月 23 日追加 ---

ありがとうございます。回答が遅れて申し訳ありませんが、変更可能なオブジェクトについても含めて、これについて詳しくお読みください http://www.javaranch.com/journal/2003/04/immutable.htm
メイン アクティビティで作成される writerThread と readerThread からこれを呼び出す方法を理解しようとしたところ、次のコードが

思いつき

ました。
...
var1W = 123;
var2W = 456;
wsW = 新しい WriterState(var1W, var2W);
appstate.setWriterState(wsW);

readerThread:


プライベート WriterState wsR;
...
wsR = appstate.getWriterState();
var1R = wsR.getVar1();
var2R = wsR.getVar2();

このコードを試してみましたが、問題なく動作するようです。var1R と var2R の読み取りの間に、新しい var1W と var2W を追加できます。

次の質問:
a) このコードは大丈夫ですか?
b) setWriterState コードがループ内にあると仮定すると、これはすべてのメモリを消費しませんか?
c) WriterState クラスを可変にするにはどうすればよいですか。ここではそうではないと思います (あなたが言う: WriterState クラスが可変である場合)

ここでも例を見ましたhttp://tutorials.jenkov.com/java-concurrency/synchronized.html . Counter オブジェクトを両方のスレッドに渡しています。この場合、このようなことはありえませんか?

4

2 に答える 2

3

の両方synchronizedとプログラムによる使用は問題ありjava.util.concurrent.Lockませんが、私は 2 番目の使用を好みます。リーダー スレッドが値の単純なチェックだけを行う必要があると仮定すると、次のような解決策があります。

編集: この方法では、リーダー スレッドは変数を読み取ることができません。AppState代わりに、読者が関心を持っているチェックはクラス内で行われます。明らかに、これは、2 つの変数を確認する必要があるものが 1 つしかなく、それが事前にわかっている場合にのみ機能します。

public class AppState
{
    private long writerVar1;
    private int writerVar2;

    private ReentrantLock lock = new ReentrantLock();

    public void setValues(long longValue, int intValue)
    {
        lock.lock();
        try
        {
            writerVar1 = longValue;
            writerVar2 = intValue;
        }
        finally
        {
            lock.unlock();
        }
    }

    public boolean isValuesCorrect()
    {
        lock.lock();
        try
        {
            return (writerVar1 == 9) && (writerVar2 == 6);
        }
        finally
        {
            lock.unlock();
        }
    }
//rest of the class body goes here
}

両方の値が である必要privateあり、同じロックを使用するメソッドによってのみアクセスされる必要があることに注意してください。そうしないと、実際にはスレッドセーフなアクセスがありません。

于 2012-04-21T17:24:01.867 に答える
3

OO 設計の鍵はカプセル化です。また、複数のスレッドを扱う場合は、さらに重要になります。これらの 2 つの変数が、一貫して更新および読み取りが必要な共有状態を構成する場合、

  • この共有状態は、この状態のすべてのクライアントが他のクライアントとのコラボレーション プロトコルを尊重することを強制するため、パブリックであってはなりません。
  • この共有状態は、状態へのアクセスを制御するオブジェクトにカプセル化する必要があります

したがって、AppState オブジェクトのフィールドは非公開にする必要があります。これは、99% のケースで当てはまるルールです。public フィールドは絶対にダメです。

次に、フィールドへのすべてのアクセスを同期する必要があります (読み取りと書き込みの両方)。これら 2 つのフィールドは 1 つの一貫した情報を構成するため、それらを 1 つのクラス (WriterState と呼びましょう) に配置する必要があります。このクラスが変更可能な場合、getState() と setState() が呼び出されるたびに共有状態によって 1 つの helf のコピーを作成する必要があるため、複数で共有できる不変クラスを使用する方が簡単で高速です。同期なしのスレッド。

/**
 * Immutable class: final, contains only final fields wich are themselves immutable.
 */
public final class WriterState {
    private final long var1;
    private final int var2;

    public WriterState(long var1, int var2) {
        this.var1 = var1;
        this.var2 = var2;
    }

    public long getVar1() {
        return this.var1;
    }

    public int getVar2() {
        return this.var2;
    }
}

public class AppState {
    private WriterState writerState;

    public synchronized void setWriterState(WriterState ws) {
        this.writerState = ws;
    }

    public synchronized WriterState getWriterState() {
        return this.writerState;
    }
}

WriterState クラスが変更可能な場合、スレッドセーフにするために次のことを行う必要があります。

public class AppState {
    private WriterState writerState;

    public synchronized void setWriterState(WriterState ws) {
        this.writerStatenew WriterState(ws.getVar1(), ws.getVar2());
    }

    public synchronized WriterState getWriterState() {
        return new WriterState(this.writerState.getVar1(), this.writerState.getVar2());
    }
}
于 2012-04-21T17:31:10.723 に答える