Polishing.

Use double checked locking to be as close to the previous implementation but still benefit from the fast read operation.

Original Pull Request: #3186
This commit is contained in:
Christoph Strobl
2024-10-29 17:27:31 +01:00
parent adc8e3ffae
commit 1b79eeb5a2
3 changed files with 58 additions and 29 deletions

View File

@@ -497,7 +497,7 @@ public class CustomConversions {
*/
static class ConversionTargetsCache {
private Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
private volatile Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
/**
* Get or compute a target type given its {@code sourceType}. Returns a cached {@link Optional} if the value
@@ -531,10 +531,19 @@ public class CustomConversions {
if (targetTypes == null) {
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
targetTypes = new TargetTypes(sourceType);
customReadTargetTypes.put(sourceType, targetTypes);
this.customReadTargetTypes = customReadTargetTypes;
synchronized (this) {
TargetTypes customReadTarget = customReadTargetTypes.get(sourceType);
if (customReadTarget != null) {
targetTypes = customReadTarget;
} else {
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
targetTypes = new TargetTypes(sourceType);
customReadTargetTypes.put(sourceType, targetTypes);
this.customReadTargetTypes = customReadTargetTypes;
}
}
}
return targetTypes.computeIfAbsent(targetType, mappingFunction);
@@ -554,7 +563,7 @@ public class CustomConversions {
static class TargetTypes {
private final Class<?> sourceType;
private Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
private volatile Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
TargetTypes(Class<?> sourceType) {
this.sourceType = sourceType;
@@ -576,11 +585,19 @@ public class CustomConversions {
if (optionalTarget == null) {
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
synchronized (this) {
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
this.conversionTargets = conversionTargets;
Class<?> conversionTarget = conversionTargets.get(targetType);
if (conversionTarget != null) {
optionalTarget = conversionTarget;
} else {
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
this.conversionTargets = conversionTargets;
}
}
}
return Void.class.equals(optionalTarget) ? null : optionalTarget;

View File

@@ -53,7 +53,7 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
private @Nullable ValueConverterRegistry<?> valueConverterRegistry;
private Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
private volatile Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
@SuppressWarnings("rawtypes")
enum NoOpConverter implements PropertyValueConverter {
@@ -171,17 +171,21 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
if (converter == null) {
converter = requireConverterFactory().getConverter(property);
synchronized (this) {
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(this.converterCache);
PropertyValueConverter<?, ?, ?> fromCache = converterCache.get(property);
if (fromCache != null) {
converter = fromCache;
} else {
if (converter == null) {
converterCache.put(property, NoOpConverter.INSTANCE);
} else {
converterCache.put(property, converter);
converter = requireConverterFactory().getConverter(property);
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(
this.converterCache);
converterCache.put(property, converter != null ? converter : NoOpConverter.INSTANCE);
this.converterCache = converterCache;
}
}
this.converterCache = converterCache;
}
if (converter == NoOpConverter.INSTANCE) {

View File

@@ -35,7 +35,7 @@ class InstanceCreatorMetadataSupport<T, P extends PersistentProperty<P>> impleme
private final Executable executable;
private final List<Parameter<Object, P>> parameters;
private Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
private volatile Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
/**
* Creates a new {@link InstanceCreatorMetadataSupport} from the given {@link Executable} and {@link Parameter}s.
@@ -90,17 +90,25 @@ class InstanceCreatorMetadataSupport<T, P extends PersistentProperty<P>> impleme
Boolean cached = isPropertyParameterCache.get(property);
if (cached != null) {
return cached;
if (cached == null) {
synchronized (this) {
Boolean fromCache = isPropertyParameterCache.get(property);
if (fromCache != null) {
cached = fromCache;
} else {
cached = doGetIsCreatorParameter(property);
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
isPropertyParameterCache.put(property, cached);
this.isPropertyParameterCache = isPropertyParameterCache;
}
}
}
boolean result = doGetIsCreatorParameter(property);
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
isPropertyParameterCache.put(property, result);
this.isPropertyParameterCache = isPropertyParameterCache;
return result;
return cached;
}
@Override