6

クラスフィールドを作成すると、同時発生の状況でのすべてのvolatileメモリの可視性の問題を防ぐことができますか?以下のクラスの場合、オブジェクトの参照を取得するスレッドは、最初に0(デフォルト値の)、次に10と見なされる可能性がありますか?これは、のコンストラクターが完了せずに参照を提供する場合にのみ可能であると考えています(不適切な公開。誰かが私を検証/修正できますか?TestxintTestthis

class Test {
    volatile int x = 10;            
}

2番目の質問:もしそうだっfinal int x=10;たら?

4

2 に答える 2

6

JMMによると、実際にはx=10であるとは限りません。

たとえば、

Test test =  null;

Thread 1 -> test = new Test();
Thread 2 -> test.x  == // even though test != null, x can be seen as 0 if the
                       // write of x hasn't yet occur

今あなたが持っていた場合

class Test{
  int y = 3;
  volatile x = 10;
}

thread-2がx==10を読み取る場合、thread-2はy==3を読み取ることが保証されます。

2番目の質問に答えます。

最終フィールドがあると、コンストラクターの後、公開する前にストアストアが発行されるため、フィールドが最終であると、実際にはx=10が表示されます。

編集:yshavitが指摘したように。私が最初の例で最後のフィールドと述べた前に起こる関係を失います。つまり、yshavitがス​​レッド2がx == 10を読み取る場合、y == 3を読み取らない可能性があります。ここで、xは最終フィールドです。

于 2012-01-06T22:06:33.860 に答える
3

シングルスレッドの実装であっても、コンストラクターでこれをリークすると、x=10になるとは限りません。したがって、ここで発生する可能性のある問題は、直接の同時実行性の問題ではなく、実行順序の問題です(これをいつリークするかによって異なります)。たとえば、これをinstaceの親コンストラクターでリークした場合:

public class TestParent
{
  public TestParent()
  {
    if (this instanceof TestChild)
    {
      TestChild child = (TestChild) this;
      System.out.println(child.field);  // will print 0 when TestChild is instantiated.
    }
  }
}


public class TestChild extends TestParent
{
  volatile int field = 10;
}

public static void main(String[] args)
{
  TestChild child = new TestChild();
  System.out.println(child.field);

  // The above results in 0 (from TestParent constructor) then 10 being printed.
}

一方、finalフィールドは、宣言行で割り当てが行われている限り、割り当てられた初期値を持つことが保証されます(フィールドをfinalにしたが、コンストラクターで初期化した場合でも、前にこれをリークして、初期化されていない値。

于 2012-01-06T22:17:05.790 に答える