Are the return values of List.copyOf(), Set.copyOf(), Map.copyOf() thread-safe?

Viewed 73

There are many questions on Stackoverflow dating back to 2008 asking if unmodifiable collections are thread-safe, but JDK 10 (released in 2018) introduced a different beast: unmodifiable copies of existing collections.

List.copyOf() states:

If the given Collection is subsequently modified, the returned List will not reflect such modifications.

Does that mean that the return value of List.copyOf(), Set.copyOf(), Map.copyOf() are all thread-safe?

(I realize that the elements contained in the collection themselves are not guaranteed to be thread-safe.)

1 Answers

Since the collections created via, e.g. List.of(…) or List.copyOf(…) do not reflect subsequent changes to the specified array or collection and are immutable in general, it’s not possible to perform modifications after construction and in absence of concurrent modifications, there can’t be any thread safety issues.

The remaining question is whether the construction of these collections itself is immune to unsafe publication. Generally, you should use the proper constructs for publishing objects to other threads and not rely on unsafe publication.

But to recall, Unmodifiable Lists say

  • They are unmodifiable. Elements cannot be added, removed, or replaced. Calling any mutator method on the List will always cause UnsupportedOperationException to be thrown. However, if the contained elements are themselves mutable, this may cause the List's contents to appear to change.

and following the value-based link, we find:

Value-based Classes

Some classes, such as java.lang.Integer and java.time.LocalDate, are value-based. A value-based class has the following properties:

  • the class declares only final instance fields (though these may contain references to mutable objects);

Final fields are important for immutable objects intended to be immune to unsafe publication. As JLS§17.5. final Field Semantics specifies:

final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. This can provide safety guarantees against misuse of an immutable class by incorrect or malicious code.

But we still have to assume the intent “to implement thread-safe immutable objects” on the JDK developer’s side rather than, e.g. the intent to surprise developers by explicitly using final fields and then deliberately spoiling the safety guarantees.

If in doubt, just use safe publication. It won’t hurt.

And even if you already said this, it’s important to emphasize that this does not apply to the contained elements if they are mutable.

Related