3

基本的には次のように機能しますが、 final キーワードについて読んだので、別のスレッドがアクセスする場合に name final を宣言する必要があるかどうかわかりませんか?

前もって感謝します。

public class Test4 {

    // to ensure thread-safety do we have to declare the variable name final ?
    private String name;

    public Test4 (String name) {
        this.name = name;
    }

    public void start() {
        new MyThread().start();
    }

    private class MyThread extends Thread {

        public void run() {
            System.out.println(name);
        }
    }

    public static void main(String[] args) {
        Test4 t = new Test4("Don't know if I am threadsafe");
        t.start();
    }

}
4

6 に答える 6

4

final修飾子は、メンバーが再割り当てされるのを防ぎますが、指定されたコードの正確性には影響しません1

Java 5 言語仕様の17.4.4 同期順序セクションから:

同期順序は、実行のすべての同期アクションに対する合計順序です。同期アクションは、次のように定義されたアクションの同期済み関係を誘導します。

  • ..
  • スレッドを開始するアクションは、それが開始するスレッド内の最初のアクションと同期します
  • ..

そして、メンバを設定したスレッドがスレッドを起動するスレッドであるため、同期順序は保証されます。(Synchronizes-with はHappens-before orderを意味します。)name

ご了承ください:

  • メンバーは、スレッドを開始する前にnameのみ設定する必要があります。つまり、この同期を保証するためにコンストラクターで設定する必要はありません。
  • これは、同期順序を保証しません。したがってすでに実行中のスレッドまたは別の場所で作成されたスレッド間で、前発生または値の可視性を保証しません。

ただし、finalフィールドはより快適な感覚を与えます (ref. 17.5 Final Field Semantics ):

コンストラクターが終了すると、オブジェクトは完全に初期化されたと見なされます。*オブジェクトが完全に初期化された後、オブジェクトへの参照のみを参照できるスレッドは、そのオブジェクトの final フィールドの正しく初期化された値を参照することが保証されます

この場合、final フィールドを使用すると、コンストラクターの完了後にすべてのスレッドで値が表示されることが保証されます。(この保証は、 「コンストラクターリーク」によって違反される可能性があります。)


1提供されたコードでは、「非最終」nameメンバーは、スレッドが開始される前に 1 回だけ割り当てられます。

それほど重要ではない別のプログラムでは、他の同期の問題が明らかになる場合がありますこの回答では、削除finalによって提供されたコードの正確さが変わるかどうかを調べます。

そうは言っても、final特にスレッドを扱う場合は、不変変数 ( ) と不変オブジェクトの両方を使用することを「良い習慣」と考えています。JVM の難解な詳細を知る必要がある代わりに、安全で証明されたものを実行し、賢さや「パフォーマンス」よりも明らかな正確さを求めて努力してください。

以下も参照してください。

于 2013-01-16T09:37:58.247 に答える
3

final 変数はimmutableです。一度構築された値は変更できないため、同時実行性の問題はありません。

于 2013-01-16T09:09:43.587 に答える
2

final がないと、フィールドの正しい値を取得できません。

フィールドの値を変更した後、スレッドが古い値を取得した可能性があります。

JMMの可視性を確認します。

volatile の別のリンク

ルールの前に発生します。

Happends-Before で JMM

于 2013-01-16T09:11:06.170 に答える
1

AtomicReferenceまたはをお探しvolatileですか?スレッドセーフの意味によって異なりますか?

// Atomic to allow deeper control of updates.
private AtomicReference<String> name = new AtomicReference<String>();
// Volatile to ensure it is not cached.
private volatile String vName;

public Test(String name) {
  this.name.set(name);
  this.vName = name;
}

public void start() {
  new MyThread().start();
}

private class MyThread extends Thread {
  public void run() {
    System.out.println(name.get());
    System.out.println(vName);
  }
}
于 2013-01-16T09:23:17.760 に答える
0

String は不変であり、フィールドを final と宣言し、フィールドの割り当て後にすべてのスレッドがそれにアクセスするため、StringBuilder が使用された場合とは対照的に、フィールドは読み取り操作にのみ使用されるため、同時発生の問題は確実に発生しません。

于 2013-01-17T10:50:32.740 に答える
0

finalマルチスレッドには何もありませんがfinal、フィールドを変更してはならず、クラスのコンストラクターで初期化する場合は、配置する必要があります。これは、後でフィールドを変更できないことを意味します。

于 2013-01-16T09:11:16.820 に答える