1

次のようなクラスの静的配列があります。

public class Entry {
    private String sharedvariable1= "";
    private String sharedvariable2= "";
    private int sharedvariable3= -1;

    private int mutablevariable1 = -1
    private int mutablevariable2 = -2;

    public Entry (String sharedvariable1, 
                  String sharedvariable2, 
                  int sharedvariable3) {
        this.sharedvariable1 = sharedvariable1;
        this.sharedvariable2 = sharedvariable2;
        this.sharedvariable3 = sharedvariable 3;
    }

    public Entry (Entry entry) {  //copy constructor. 
        this (entry.getSharedvariable1, 
              entry.getSharedvariable2, 
              entry.getSharedvaraible3);
    }
....
/* other methods including getters and setters*/
}

プログラムのある時点で、このオブジェクトのインスタンスにアクセスし、上記のコピーコンストラクターを使用してそのコピーを作成します。次に、上記の2つの可変変数の値を変更します。このプログラムはマルチスレッド環境で実行されています。 ご注意ください。すべての変数は、スレッド化の前に初期値で設定されます。 プログラムがスレッド化された後でのみ、コピーが作成され、変数が変更されます。私は静的オブジェクトを読み取り、書き込みを行わず(intとmutableは読み取りのみですが、共有変数3も)、静的オブジェクトのコピーにのみ変更を加えているため、スレッドセーフであると信じています(およびコピーはスレッド内で作成されています)。しかし、ここで私の考えが正しいことを確認したいと思います。

誰かが私がしていることを評価してもらえますか?

4

5 に答える 5

3

スレッドセーフではありません。したがって、共有変数を変更するものはすべてラップする必要があります。

synchronized (this) {
    this.sharedvariable1 = newValue;
}

セッターの場合、代わりにこれを行うことができます:

public synchronized void setSharedvariable1(String sharedvariable1) {
    this.sharedvariable1 = sharedvariable1;
}

次に、コピー コンストラクターで、同様に行います。

public Entry (Entry entry) {
    this();
    synchronized(entry) {
        this.setSharedvariable1(entry.getSharedvariable1());
        this.setSharedvariable2(entry.getSharedvariable2());
        this.setSharedvariable3(entry.getSharedvariable3());
    }
}

これにより、インスタンスに変更が加えられている場合、コピー操作は変更が完了するまで待機します。

于 2012-04-17T12:48:58.260 に答える
0

プライベートインスタンス変数を共有と見なす理由がよくわかりません。通常、共有フィールドは静的でプライベートではありません。プライベート インスタンス変数を共有しないことをお勧めします。スレッドセーフのために、変数値を変更する操作を同期する必要があります。

そのために synchronized キーワードを使用できますが、正しい監視オブジェクトを選択してください (エントリ自体で行うべきだと思います)。もう 1 つの方法は、java.util.concurrent のロックの実装を使用することです。通常、ロックはより高いスループットと優れた粒度を提供します (たとえば、複数の並列読み取りが常に 1 つの書き込みのみであるなど)。

考えなければならないもう 1 つのことは、いわゆるメモリ バリアです。この興味深い記事をご覧くださいhttp://java.dzone.com/articles/java-memory-model-programer%E2%80%99s

volatile キーワードを使用してセマンティックの前に発生を強制できます。明示的な同期 (ロックまたは同期されたコード) も、メモリ バリアを越えて、セマンティクスの前に発生するように強制します。

最後に一般的なアドバイス: 変更可能な状態を共有することは絶対に避けてください。同期はお尻の痛みです (パフォーマンスとメンテナンスに関して)。不適切な同期に起因するバグを検出するのは非常に困難です。不変性または分離された可変性 (アクターなど) を設計することをお勧めします。

于 2012-04-17T13:15:11.867 に答える
0

スレッドセーフではないため、コピー コンストラクターで同期する必要があります。コピー コンストラクターで、元のオブジェクトから 3 つの変数をそれぞれ読み取っています。これらの操作は一緒にアトミックではありません。したがって、最初の値を読み取っている間に、3 番目の値が別のスレッドによって変更される可能性があります。この場合、一貫性のない状態の「コピーされた」オブジェクトがあります。

于 2012-04-17T12:47:27.653 に答える
0

スレッドセーフではありません。つまり、同じインスタンスを使用する複数のスレッドのスレッド セーフは保証されません。Entry

ここで見られる問題は次のとおりです。

  1. Thread 1インスタンスの構築を開始しEntryます。そのインスタンスが他のスレッド アクセスから隠されているわけではありません。
  2. Thread 2は、そのコピー コンストラクターを使用してそのインスタンスにアクセスしますが、それはまだ構築の途中です。

Entryの field の初期値を考慮すると、private int sharedvariable3= -1;によって作成された新しい「コピーされた」インスタンスのフィールドが (Java の int クラス フィールドのデフォルト) に設定される可能性がThread 2ありますsharedvariable30

それが問題です。

気になる場合はsynchronize、読み取り/書き込み操作を行うか、Entryインスタンスの公開を処理する必要があります。Entryつまり、構築中のインスタンスへの他のスレッドのアクセスを許可しないでください。

于 2012-04-17T13:07:50.467 に答える
0

答えは、静的な状態の変数からのみ読み取り、コピーのみを変更するため、概説した条件下でスレッドセーフであるということです。

于 2012-04-28T21:39:34.833 に答える