Skip to content

Commit 3103fa9

Browse files
Use double checked locking.
Try to be as close to the previous implementation but still benefit from the non locking read operation.
1 parent f06fff4 commit 3103fa9

File tree

3 files changed

+57
-28
lines changed

3 files changed

+57
-28
lines changed

src/main/java/org/springframework/data/convert/CustomConversions.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ private Class<?> getCustomTarget(Class<?> sourceType, @Nullable Class<?> targetT
497497
*/
498498
static class ConversionTargetsCache {
499499

500-
private Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
500+
private volatile Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
501501

502502
/**
503503
* Get or compute a target type given its {@code sourceType}. Returns a cached {@link Optional} if the value
@@ -531,10 +531,19 @@ public Class<?> computeIfAbsent(Class<?> sourceType, Class<?> targetType,
531531

532532
if (targetTypes == null) {
533533

534-
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
535-
targetTypes = new TargetTypes(sourceType);
536-
customReadTargetTypes.put(sourceType, targetTypes);
537-
this.customReadTargetTypes = customReadTargetTypes;
534+
synchronized (this) {
535+
536+
TargetTypes customReadTarget = customReadTargetTypes.get(sourceType);
537+
if (customReadTarget != null) {
538+
targetTypes = customReadTarget;
539+
} else {
540+
541+
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
542+
targetTypes = new TargetTypes(sourceType);
543+
customReadTargetTypes.put(sourceType, targetTypes);
544+
this.customReadTargetTypes = customReadTargetTypes;
545+
}
546+
}
538547
}
539548

540549
return targetTypes.computeIfAbsent(targetType, mappingFunction);
@@ -554,7 +563,7 @@ interface AbsentTargetTypeMarker {}
554563
static class TargetTypes {
555564

556565
private final Class<?> sourceType;
557-
private Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
566+
private volatile Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
558567

559568
TargetTypes(Class<?> sourceType) {
560569
this.sourceType = sourceType;
@@ -576,11 +585,19 @@ public Class<?> computeIfAbsent(Class<?> targetType, Function<ConvertiblePair, C
576585

577586
if (optionalTarget == null) {
578587

579-
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
588+
synchronized (this) {
589+
590+
Class<?> conversionTarget = conversionTargets.get(targetType);
591+
if (conversionTarget != null) {
592+
optionalTarget = conversionTarget;
593+
} else {
580594

581-
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
582-
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
583-
this.conversionTargets = conversionTargets;
595+
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
596+
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
597+
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
598+
this.conversionTargets = conversionTargets;
599+
}
600+
}
584601
}
585602

586603
return Void.class.equals(optionalTarget) ? null : optionalTarget;

src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
5353

5454
private @Nullable ValueConverterRegistry<?> valueConverterRegistry;
5555

56-
private Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
56+
private volatile Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
5757

5858
@SuppressWarnings("rawtypes")
5959
enum NoOpConverter implements PropertyValueConverter {
@@ -171,17 +171,21 @@ private <DV, SV, P extends PersistentProperty<P>, D extends ValueConversionConte
171171

172172
if (converter == null) {
173173

174-
converter = requireConverterFactory().getConverter(property);
174+
synchronized (this) {
175175

176-
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(this.converterCache);
176+
PropertyValueConverter<?, ?, ?> fromCache = converterCache.get(property);
177+
if (fromCache != null) {
178+
converter = fromCache;
179+
} else {
177180

178-
if (converter == null) {
179-
converterCache.put(property, NoOpConverter.INSTANCE);
180-
} else {
181-
converterCache.put(property, converter);
182-
}
181+
converter = requireConverterFactory().getConverter(property);
183182

184-
this.converterCache = converterCache;
183+
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(
184+
this.converterCache);
185+
converterCache.put(property, converter != null ? converter : NoOpConverter.INSTANCE);
186+
this.converterCache = converterCache;
187+
}
188+
}
185189
}
186190

187191
if (converter == NoOpConverter.INSTANCE) {

src/main/java/org/springframework/data/mapping/InstanceCreatorMetadataSupport.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class InstanceCreatorMetadataSupport<T, P extends PersistentProperty<P>> impleme
3535

3636
private final Executable executable;
3737
private final List<Parameter<Object, P>> parameters;
38-
private Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
38+
private volatile Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
3939

4040
/**
4141
* Creates a new {@link InstanceCreatorMetadataSupport} from the given {@link Executable} and {@link Parameter}s.
@@ -90,17 +90,25 @@ public boolean isCreatorParameter(PersistentProperty<?> property) {
9090

9191
Boolean cached = isPropertyParameterCache.get(property);
9292

93-
if (cached != null) {
94-
return cached;
95-
}
93+
if (cached == null) {
94+
95+
synchronized (this) {
96+
97+
Boolean fromCache = isPropertyParameterCache.get(property);
98+
if (fromCache != null) {
99+
cached = fromCache;
100+
} else {
96101

97-
boolean result = doGetIsCreatorParameter(property);
102+
cached = doGetIsCreatorParameter(property);
98103

99-
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
100-
isPropertyParameterCache.put(property, result);
101-
this.isPropertyParameterCache = isPropertyParameterCache;
104+
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
105+
isPropertyParameterCache.put(property, cached);
106+
this.isPropertyParameterCache = isPropertyParameterCache;
107+
}
108+
}
109+
}
102110

103-
return result;
111+
return cached;
104112
}
105113

106114
@Override

0 commit comments

Comments
 (0)