2012-01-06 4 views
6

클래스 필드를 만들면 이 발생하지 않습니다. 동시 발생 상황에서 메모리 가시성 문제가 있습니까? 아래 클래스의 경우 Test 개체의 참조를 가져 오는 스레드가 을 먼저 0 (기본값은 int)으로보고 10을 볼 수 있습니까? 가능한 경우 이라고 생각하고 있습니다. Test의 생성자이 완료되지 않은 경우 (부적절한 게시) this 참조를 제공하는 경우에만 해당합니다. 누군가가 나를 검증/교정 할 수 있습니까?'volatile'필드를 사용하면 동시 발생 상황에서 모든 메모리 가시성 문제를 방지 할 수 있습니까?

class Test { 
    volatile int x = 10;    
} 

두 번째 질문 : final int x=10;은 무엇 이었습니까?

답변

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; 
} 

스레드 2의 X ==를 읽는 경우 10 스레드 2 y를 ==를 읽을 보장 3

두 번째 질문에 답하십시오.

은 최종 필드 생성자 후 실제로 보장합니다 필드 마지막을 이렇게 게시 가진 전에 storestore를 발행합니다 갖는 당신은 X = 10

편집을 참조하십시오 yshavit가 언급 한 바와 같이. 내가 마지막 필드와 함께 첫 번째 예제에서 언급 한 happen-before 관계를 잃어 버린다. yshavit은 thread-2가 x == 10이면 y == 3을 읽을 수 없다. x는 최종 필드이다.

+0

첫 번째 코드 스 니펫을 참조하면 'test'라는 참조가 'final'으로 선언되면 다음과 같이됩니다. 'test! = null'이 참이라면 Thread 2는'test.x'를 10으로 보게됩니다. – Bhaskar

+1

그러나 명확히하기 위해'x'가 마지막으로 thread-2가'x == 10'을 읽으면'y == 3'을 읽어야한다는 보장을 잃게됩니다. – yshavit

+1

@Bhaskar 네,'this'가'Test'의 생성자에서 유출되지 않는 한. '누설 '이라면 모든 내기가 꺼져 있습니다. – yshavit

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로 만들고 생성자에서 초기화하면 이이 앞에 표시되고 초기화되지 않은 값이 표시됩니다.

+0

그건 _instance 초기화 blocks_ 편리하게되면, 어떤 생성자가 호출되기 전에 당신은 펑키 멀티 라인 assigments/계산을 할 수 :) –