공부

java의 field 초기화와 동시성

프로필사진
fienestar
2023. 6. 15. 19:51

다음 코드의 출력을 예상해보자.

class A{
    A() {
        f();
    }

    public void f(){
        System.out.println("3");
    }
}

class B extends A{
    int x = 4;
    public void f() {
        System.out.println(x);
    }
}

public class Main {
    public static void main(String[] args) {
        A a = new B();
    }
}

답은 뭘까? 3 혹은 4중에 고민하고 있다면, 그렇지 않다. 답은 0이다.

 

java는 C++와 다르게 생성자에서도 virtual하고 순서상 A가 초기화된 후에 B가 초기화되기 때문에, x가 초기화되지 않은 상태로 출력되어 0이 출력된다.

 

그렇다면 생성자에서 필드를 초기화하는 클래스에 대해 객체의 참조가 저장된(a = new A()) 이후라면 항상 필드가 초기화되어있을까?

 

상상해보면 new A() 라는 표현식이 평가되고 난 후에 참조가 저장되었을 것이므로, 생성자가 호출되어 필드의 초기화를 보장할 것 같다. 다음 코드를 보자

// jls(java lang spec) 17의 17.5-1 예제를 약간 수정했다.
class A {
    int x;
    static A a;
    public A() {
        x = 4;
    }
    static void writer() {
        a = new A();
    }
    static boolean reader() {
        if (a != null) {
            System.out.println(a.x);
        }
    }
}

멀티 스레드 환경에서 한 스레드는 writer()를 호출하고, 다른 스레드는 reader()를 호출할 때, 만약 reader()a != null이 참으로 평가되면, 4가 출력될까?

 

jls는 이를 보장하지 않는다. 오히려 0을 출력할 수 있다고 말한다.

 

즉, 객체의 참조가 저장된 시점에조차 construtor가 완료되었음을 보장하지 않는다. a에 대한 assign이 x에 대한 assign보다 선행될 수 있다.

the reader method is therefore not guaranteed to see the value 4 for it.

두 케이스 모두 x에 final을 지정하면 초기화된 값을 보여줌을 보장한다.

 

final은 단순히 수정하지 못하게 하는 역할을 수행하는 것 뿐만 아니라 안전하게 초기화됨이 보장된다.

this is test for configure something