Are Java Static Initializers Thread Safe

Are Java static initializers thread safe?

Yes, Java static initializers are thread safe (use your first option).

However, if you want to ensure that the code is executed exactly once you need to make sure that the class is only loaded by a single class-loader. Static initialization is performed once per class-loader.

Java static block thread safety

You wrote

Even if I have a static block AND a separate static initialization of a map!

which shows a wrong mindset. You don’t have separate initializations.

The code

public class DatabaseQueries {
private static Map<DatabaseActions, String> database = new HashMap<>();
static {
database.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
}
}

is identical to

public class DatabaseQueries {
private static Map<DatabaseActions, String> database;
static {
database = new HashMap<>();
database.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
}
}

All initializers of static fields (except for compile-time constants) are merged with all static {} blocks into a single initializer, in the order of their appearance in the class declaration.

The thread safety applies to the completion of that single resulting initializer and subsequent reads of the initialized data.

So if the map is never modified after the class initialization, it is thread safe. It’s not necessary, but strongly recommended, to enforce the “no modification after initialization” rule:

public class DatabaseQueries {

private static final Map<DatabaseActions, String> database;
static { // keep variable declaration and initializer close for readability
Map<DatabaseActions, String> map = new HashMap<>();// mutable ref during initialization
map.put(
DatabaseActions.LIST_CHIHUAHUA,
"SELECT id, nome, immagine FROM chihuahua ORDER BY data_nascita DESC"
);
// more...
database = Collections.unmodifiableMap(map);// enforce read-only
}

public static Map<DatabaseActions, String> getDatabase() {
return database;// no wrapping necessary, it’s already wrapped
}
}

Thread safety of static blocks in Java

If the first thread hasn't finished initializing SomeClass, the second thread will block.

This is detailed in the Java Language Specification in section 12.4.2.

Java static initialization thread safety guarantee in language spec

I believe this is effectively a result of the rules for class initialization in JLS 12.4.2. That involves synchronizing on a lock, only releasing it after executing the static initializers and field initializers. That lock acquisition and release then affects the "happens before" part of the thread model, via JLS 17.4.4 (I think - I'm not an expert on this).

Note that 12.4.2 states:

An implementation may optimize this procedure by eliding the lock acquisition in step 1 (and release in step 4/5) when it can determine that the initialization of the class has already completed, provided that, in terms of the memory model, all happens-before orderings that would exist if the lock were acquired, still exist when the optimization is performed.

Static variable initialization during declaration in multi-threading

The answer is given by the Java Language Specification §12.4.2:

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface; for example, a variable initializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure. […]

Note the last sentence starting with “The implementation of the Java Virtual Machine is responsible for taking care …”

So you are not responsible for synchronization in the case of class initialization, and assigning initial values to static variables is part of the class initialization, as specified in §8.3.2:

8.3.2. Field Initialization

If a declarator in a field declaration has a variable initializer, then the declarator has the semantics of an assignment (§15.26) to the declared variable.

If the declarator is for a class variable (that is, a static field), then the following rules apply to its initializer:

  • At run time, the initializer is evaluated and the assignment performed exactly once, when the class is initialized (§12.4.2).

Java static factory to create not thread safe object

There isn't anything about the static-ness, or anything about the factory method, that magically makes something thread-safe that otherwise isn't.

I assume the strategy he's trying to recommend is that every time a piece of code wants a SimpleDateFormat which represents that format, then rather than rely on some instance which is lying around (which may be used by any number of threads), then it should call this factory method instead. i.e. almost every SimpleDateFormat will get used exactly once, then garbage collected.

I'm not sure why he's contrasting that with a static initializer specifically. I suppose this is what he had in mind.
Since multiple threads may access FORMAT, any that do are not thread-safe.

class Foo {
private static final SimpleDateFormat FORMAT = new SimpleDateFormat();

static {
// Uncle Bob disapproves
format.setTimeZone(TimeZone.getTimeZone("GMT"));
}
}

The factory method is one strategy, but it's not a great one. It ensures that every caller that relies on makeStandardHttpDateFormat as intended will be thread-safe, but it does not guarantee that every caller will rely on makeStandardHttpDateFormat.

A much better strategy would be to use some immutable variant, like DateTimeFormatter.

Is this thread-safe in Java?

Yes, that is thread safe. static initializer blocks are run when the class is initialized and that is done behind a lock. So mySet is initialized fully before it is published (made available). All threads will see it fully constructed.

Is initialized non final static variables are thread safe?

I just wanted to know what guarantee JVM provides with non final static variables with no methods to modify the variable in terms of thread safety, where multiple threads try to read the data.

The procedure for initializing a class (JLS 11.4.2) states that that initialization is performed while holding a lock. I think that this implies that any thread that refers to the statics after initialization has completed will see the fully initialized state.

You might get into trouble if you had a situation where the static initialization of one class created and started a thread that could observe the static variables of another class before they latter's static initialization completed. In that case, it may not be possible to guarantee that the thread will see the initialized state.


The other think to note is that we are only talking about the values in the static variables here. If those variables refer to mutable objects or arrays, and those objects / arrays are mutated, then your code is not automatically thread-safe.

This illustrates a larger point. You can't actually talk about the thread-safety of variables in isolation. The accepted definition of thread-safety is that the introduction of threading does not result in incorrect behaviour of something. Variables don't have behaviour. Behaviour is an application level thing, though it is sometimes meaningful to consider the behaviour of a part of an application; e.g. some classes or methods in a particular application context.


Reading between the lines ... you seem to be trying to avoid the "overheads" of synchronization in your usage of statics. That is all well and good ... but the thread-safety, static initialization and the memory model are all some of the most difficult / hard to understand parts of the Java language. Many really smart people have (in the past) tried and failed when implementing "clever" or "efficient" ways of reducing synchronization overheads.

My advice: don't try to be too smart. Keep it simple. The synchronization overheads are not large enough (IMO) to risk introducing "heisenbugs" into your code-base.

And finally, it is generally accepted that static variables, and especially mutable static variables are bad OO design. I would advise you to consider revising your design to eliminate them.

Are final static variables thread safe in Java?

the reference to sharedData which is final is thread safe since it can never be changed. The contents of the Map is NOT thread safe because it needs to be either wrapped with preferably a Guava ImmutableMap implementation or java.util.Collections.unmodifiableMap() or use one of the Map implementations in the java.util.concurrent package.

Only if you do BOTH will you have comprehensive thread safety on the Map. Any contained Maps need to be immutable or one of the concurrent implementations as well.

.clone() is fundamentally broken, stay away

cloning by default is a shallow clone, it will just return references to container objects not complete copies. It is well documented in generally available information on why.



Related Topics



Leave a reply



Submit