Mark value fields in ReflectProperties as volatile
These fields were originally non-volatile because of an incorrect assumption I had at the time that a value was safely published if the underlying object's class has at least one final field. This is true for almost all values used in lazy/lazySoft: DeserializedFunctionDescriptor, DeserializedPropertyDescriptor, KTypeImpl, java.lang.reflect.Field, etc. But of course, this only means that the object was _safely initialized_ and not safely published via the non-volatile reference, where other threads can still observe null, even after that constructed object was leaked to the outer world by some other means and led to observable changes in behavior. This can fix some concurrency issues in kotlin-reflect. I wasn't able to reproduce the problem in stress tests though.
This commit is contained in:
@@ -46,7 +46,7 @@ public class ReflectProperties {
|
||||
// A delegate for a lazy property, whose initializer may be invoked multiple times including simultaneously from different threads
|
||||
public static class LazyVal<T> extends Val<T> {
|
||||
private final Function0<T> initializer;
|
||||
private Object value = null;
|
||||
private volatile Object value = null;
|
||||
|
||||
public LazyVal(@NotNull Function0<T> initializer) {
|
||||
this.initializer = initializer;
|
||||
@@ -70,7 +70,7 @@ public class ReflectProperties {
|
||||
// including simultaneously from different threads
|
||||
public static class LazySoftVal<T> extends Val<T> {
|
||||
private final Function0<T> initializer;
|
||||
private SoftReference<Object> value = null;
|
||||
private volatile SoftReference<Object> value = null;
|
||||
|
||||
public LazySoftVal(@Nullable T initialValue, @NotNull Function0<T> initializer) {
|
||||
this.initializer = initializer;
|
||||
|
||||
Reference in New Issue
Block a user