1

Per the JMM, section 9.2.3

The rules for class initialization ensure that any thread that reads a static field will be synchronized with the static initialization of that class.

I am trying to understand what happens when a class (b) attempts to read a static field from class (a), and (a) is still being initialized. Is there any guarantee that (b) will read the correct value of (a) (i.e. after static initialization)?

As an example, is there a data race on field_long?

class TextField {
    public static final FieldType TEXT_FIELD_TYPE = new FieldType();

    static {
        TEXT_FIELD_TYPE.set_field_long(1L);
    };
}

class FieldType {
    public Long field_long;

    public void set_field_long(Long l) { field_long = l; }
    public Long get_field_long() { return field_long; }

    public FieldType(){ set_field_long(-1L); }
    public FieldType(FieldType ref) { this.field_long = ref.get_field_long(); }
}

public class Main {
    public static void main(String... args) {
        Thread t1 = new Thread(() -> {
            FieldType f = new FieldType(TextField.TEXT_FIELD_TYPE);
        });

        Thread t2 = new Thread(() -> {
            FieldType f = new FieldType(TextField.TEXT_FIELD_TYPE);
        });

       t1.start();
       t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
4
  • 1
    There is no race condition: static initialization of a class Is guaranteed to be complete before another class can use it, including reading static fields. Commented Oct 8, 2024 at 2:24
  • In other words, it isn't even possible for a class to see a static field until the initializer and class loader are done. If you call MyClass.afield on a class that isn't loaded yet, the class loading happens first, then all initialization, then your code continues executing with the class now loaded in the system. Commented Oct 8, 2024 at 3:09
  • So in the example you give, first the class Main is loaded, then main begins executing, then Thread gets loaded, then (likely) the parameter TextField is evaluated and that class is loaded, then FieldType class is loaded, and only then does the code continue to t1.start(). Commented Oct 8, 2024 at 3:12
  • @Bohemian that sounds like it should be an answer, not a comment, so that people can vote on it and OP can (possibly) accept it. Commented Oct 8, 2024 at 5:37

1 Answer 1

1

The race condition does not occur because the JVM synchronizes the loading and initialization of classes using initialization locking mechanism, as specified in the Java Virtual Machine Specification. Unfortunately, during synchronization, the threads do not change their state to BLOCKED and are still in the RUNNABLE state, but the presence of synchronization can be confirmed using a simple example of a deadlock:

public class DeadlockDemo {

    static class A {
        static final B b = new B();
    }

    static class B {
        static final A a = new A();
    }

    public static void main(String[] args) {
        new Thread(A::new).start();
        new B();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.