Skip to content

Commit 2668e5f

Browse files
Replace most usage of synchronized with ReentrantLock
1 parent 48124cd commit 2668e5f

File tree

7 files changed

+86
-16
lines changed

7 files changed

+86
-16
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.lang.reflect.Constructor;
55
import java.lang.reflect.InvocationTargetException;
66
import java.util.*;
7+
import java.util.concurrent.locks.ReentrantLock;
78

89
import com.fasterxml.jackson.annotation.*;
910

@@ -180,6 +181,8 @@ public abstract class BeanDeserializerBase
180181
*/
181182
protected transient HashMap<ClassKey, JsonDeserializer<Object>> _subDeserializers;
182183

184+
private final ReentrantLock _subDeserializersLock = new ReentrantLock();
185+
183186
/**
184187
* If one of properties has "unwrapped" value, we need separate
185188
* helper object
@@ -1885,8 +1888,11 @@ protected JsonDeserializer<Object> _findSubclassDeserializer(DeserializationCont
18851888
JsonDeserializer<Object> subDeser;
18861889

18871890
// First: maybe we have already created sub-type deserializer?
1888-
synchronized (this) {
1891+
try {
1892+
_subDeserializersLock.lock();
18891893
subDeser = (_subDeserializers == null) ? null : _subDeserializers.get(new ClassKey(bean.getClass()));
1894+
} finally {
1895+
_subDeserializersLock.unlock();
18901896
}
18911897
if (subDeser != null) {
18921898
return subDeser;
@@ -1902,11 +1908,14 @@ protected JsonDeserializer<Object> _findSubclassDeserializer(DeserializationCont
19021908
subDeser = ctxt.findRootValueDeserializer(type);
19031909
// Also, need to cache it
19041910
if (subDeser != null) {
1905-
synchronized (this) {
1911+
try {
1912+
_subDeserializersLock.lock();
19061913
if (_subDeserializers == null) {
19071914
_subDeserializers = new HashMap<ClassKey,JsonDeserializer<Object>>();;
19081915
}
19091916
_subDeserializers.put(new ClassKey(bean.getClass()), subDeser);
1917+
} finally {
1918+
_subDeserializersLock.unlock();
19101919
}
19111920
}
19121921
return subDeser;

src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.lang.reflect.Constructor;
55
import java.text.*;
66
import java.util.*;
7+
import java.util.concurrent.locks.ReentrantLock;
78

89
import com.fasterxml.jackson.annotation.JsonFormat;
910

@@ -69,6 +70,8 @@ protected abstract static class DateBasedDeserializer<T>
6970
*/
7071
protected final DateFormat _customFormat;
7172

73+
private final ReentrantLock _customFormatLock = new ReentrantLock();
74+
7275
/**
7376
* Let's also keep format String for reference, to use for error messages
7477
*/
@@ -188,13 +191,16 @@ protected java.util.Date _parseDate(JsonParser p, DeserializationContext ctxt)
188191
}
189192
return null;
190193
}
191-
synchronized (_customFormat) {
194+
try {
195+
_customFormatLock.lock();
192196
try {
193197
return _customFormat.parse(str);
194198
} catch (ParseException e) {
195199
return (java.util.Date) ctxt.handleWeirdStringValue(handledType(), str,
196200
"expected format \"%s\"", _formatString);
197201
}
202+
} finally {
203+
_customFormatLock.unlock();
198204
}
199205
}
200206
}

src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.fasterxml.jackson.databind.util.CompactStringObjectMap;
2121
import com.fasterxml.jackson.databind.util.EnumResolver;
2222
import java.util.Optional;
23+
import java.util.concurrent.locks.ReentrantLock;
2324

2425
/**
2526
* Deserializer class that can deserialize instances of
@@ -54,6 +55,8 @@ public class EnumDeserializer
5455
*/
5556
protected volatile CompactStringObjectMap _lookupByToString;
5657

58+
private final ReentrantLock _lookupLock = new ReentrantLock();
59+
5760
protected final Boolean _caseInsensitive;
5861

5962
private Boolean _useDefaultValueForUnknownEnum;
@@ -472,13 +475,16 @@ protected Class<?> _enumClass() {
472475
protected CompactStringObjectMap _getToStringLookup(DeserializationContext ctxt) {
473476
CompactStringObjectMap lookup = _lookupByToString;
474477
if (lookup == null) {
475-
synchronized (this) {
478+
try {
479+
_lookupLock.lock();
476480
lookup = _lookupByToString;
477481
if (lookup == null) {
478482
lookup = EnumResolver.constructUsingToString(ctxt.getConfig(), _enumClass())
479483
.constructLookup();
480484
_lookupByToString = lookup;
481485
}
486+
} finally {
487+
_lookupLock.unlock();
482488
}
483489
}
484490
return lookup;

src/main/java/com/fasterxml/jackson/databind/deser/std/StdKeyDeserializer.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.net.URI;
99
import java.net.URL;
1010
import java.util.*;
11+
import java.util.concurrent.locks.ReentrantLock;
1112

1213
import com.fasterxml.jackson.core.JsonParser;
1314
import com.fasterxml.jackson.core.io.NumberInput;
@@ -390,6 +391,8 @@ final static class EnumKD extends StdKeyDeserializer
390391
*/
391392
protected final EnumResolver _byEnumNamingResolver;
392393

394+
private final ReentrantLock _resolverLock = new ReentrantLock();
395+
393396
protected final Enum<?> _enumDefaultValue;
394397

395398
protected EnumKD(EnumResolver er, AnnotatedMethod factory) {
@@ -472,13 +475,16 @@ private EnumResolver _getToStringResolver(DeserializationContext ctxt)
472475
{
473476
EnumResolver res = _byToStringResolver;
474477
if (res == null) {
475-
synchronized (this) {
478+
try {
479+
_resolverLock.lock();
476480
res = _byToStringResolver;
477481
if (res == null) {
478482
res = EnumResolver.constructUsingToString(ctxt.getConfig(),
479483
_byNameResolver.getEnumClass());
480484
_byToStringResolver = res;
481485
}
486+
} finally {
487+
_resolverLock.unlock();
482488
}
483489
}
484490
return res;
@@ -495,13 +501,16 @@ private EnumResolver _getToStringResolver(DeserializationContext ctxt)
495501
private EnumResolver _getIndexResolver(DeserializationContext ctxt) {
496502
EnumResolver res = _byIndexResolver;
497503
if (res == null) {
498-
synchronized (this) {
504+
try {
505+
_resolverLock.lock();
499506
res = _byIndexResolver;
500507
if (res == null) {
501508
res = EnumResolver.constructUsingIndex(ctxt.getConfig(),
502509
_byNameResolver.getEnumClass());
503510
_byIndexResolver = res;
504511
}
512+
} finally {
513+
_resolverLock.unlock();
505514
}
506515
}
507516
return res;

src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44
import java.util.Map;
55
import java.util.concurrent.ConcurrentHashMap;
6+
import java.util.concurrent.locks.ReentrantLock;
67

78
import com.fasterxml.jackson.annotation.JsonTypeInfo;
89

@@ -42,6 +43,8 @@ public abstract class TypeDeserializerBase
4243
*/
4344
protected final JavaType _defaultImpl;
4445

46+
protected final ReentrantLock _defaultImplLock = new ReentrantLock();
47+
4548
/**
4649
* Name of type property used; needed for non-property versions too,
4750
* in cases where type id is to be exposed as part of JSON.
@@ -223,12 +226,15 @@ protected final JsonDeserializer<Object> _findDefaultImplDeserializer(Deserializ
223226
return NullifyingDeserializer.instance;
224227
}
225228

226-
synchronized (_defaultImpl) {
229+
try {
230+
_defaultImplLock.lock();
227231
if (_defaultImplDeserializer == null) {
228232
_defaultImplDeserializer = ctxt.findContextualValueDeserializer(
229233
_defaultImpl, _property);
230234
}
231235
return _defaultImplDeserializer;
236+
} finally {
237+
_defaultImplLock.unlock();
232238
}
233239
}
234240

src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.fasterxml.jackson.databind.ser;
22

33
import java.util.concurrent.atomic.AtomicReference;
4+
import java.util.concurrent.locks.ReentrantLock;
45

56
import com.fasterxml.jackson.databind.*;
67
import com.fasterxml.jackson.databind.ser.impl.ReadOnlyClassToSerializerMap;
@@ -45,6 +46,8 @@ public final class SerializerCache
4546
*/
4647
private final LookupCache<TypeKey, JsonSerializer<Object>> _sharedMap;
4748

49+
private final ReentrantLock _sharedMapLock = new ReentrantLock();
50+
4851
/**
4952
* Most recent read-only instance, created from _sharedMap, if any.
5053
*/
@@ -107,29 +110,41 @@ public synchronized int size() {
107110
*/
108111
public JsonSerializer<Object> untypedValueSerializer(Class<?> type)
109112
{
110-
synchronized (this) {
113+
try {
114+
_sharedMapLock.lock();
111115
return _sharedMap.get(new TypeKey(type, false));
116+
} finally {
117+
_sharedMapLock.unlock();
112118
}
113119
}
114120

115121
public JsonSerializer<Object> untypedValueSerializer(JavaType type)
116122
{
117-
synchronized (this) {
123+
try {
124+
_sharedMapLock.lock();
118125
return _sharedMap.get(new TypeKey(type, false));
126+
} finally {
127+
_sharedMapLock.unlock();
119128
}
120129
}
121130

122131
public JsonSerializer<Object> typedValueSerializer(JavaType type)
123132
{
124-
synchronized (this) {
133+
try {
134+
_sharedMapLock.lock();
125135
return _sharedMap.get(new TypeKey(type, true));
136+
} finally {
137+
_sharedMapLock.unlock();
126138
}
127139
}
128140

129141
public JsonSerializer<Object> typedValueSerializer(Class<?> cls)
130142
{
131-
synchronized (this) {
143+
try {
144+
_sharedMapLock.lock();
132145
return _sharedMap.get(new TypeKey(cls, true));
146+
} finally {
147+
_sharedMapLock.unlock();
133148
}
134149
}
135150

@@ -146,29 +161,36 @@ public JsonSerializer<Object> typedValueSerializer(Class<?> cls)
146161
*/
147162
public void addTypedSerializer(JavaType type, JsonSerializer<Object> ser)
148163
{
149-
synchronized (this) {
164+
try {
165+
_sharedMapLock.lock();
150166
if (_sharedMap.put(new TypeKey(type, true), ser) == null) {
151167
// let's invalidate the read-only copy, too, to get it updated
152168
_readOnlyMap.set(null);
153169
}
170+
} finally {
171+
_sharedMapLock.unlock();
154172
}
155173
}
156174

157175
public void addTypedSerializer(Class<?> cls, JsonSerializer<Object> ser)
158176
{
159-
synchronized (this) {
177+
try {
178+
_sharedMapLock.lock();
160179
if (_sharedMap.put(new TypeKey(cls, true), ser) == null) {
161180
// let's invalidate the read-only copy, too, to get it updated
162181
_readOnlyMap.set(null);
163182
}
183+
} finally {
184+
_sharedMapLock.unlock();
164185
}
165186
}
166187

167188
public void addAndResolveNonTypedSerializer(Class<?> type, JsonSerializer<Object> ser,
168189
SerializerProvider provider)
169190
throws JsonMappingException
170191
{
171-
synchronized (this) {
192+
try {
193+
_sharedMapLock.lock();
172194
if (_sharedMap.put(new TypeKey(type, false), ser) == null) {
173195
_readOnlyMap.set(null);
174196
}
@@ -180,14 +202,17 @@ public void addAndResolveNonTypedSerializer(Class<?> type, JsonSerializer<Object
180202
if (ser instanceof ResolvableSerializer) {
181203
((ResolvableSerializer) ser).resolve(provider);
182204
}
205+
} finally {
206+
_sharedMapLock.unlock();
183207
}
184208
}
185209

186210
public void addAndResolveNonTypedSerializer(JavaType type, JsonSerializer<Object> ser,
187211
SerializerProvider provider)
188212
throws JsonMappingException
189213
{
190-
synchronized (this) {
214+
try {
215+
_sharedMapLock.lock();
191216
if (_sharedMap.put(new TypeKey(type, false), ser) == null) {
192217
_readOnlyMap.set(null);
193218
}
@@ -199,6 +224,8 @@ public void addAndResolveNonTypedSerializer(JavaType type, JsonSerializer<Object
199224
if (ser instanceof ResolvableSerializer) {
200225
((ResolvableSerializer) ser).resolve(provider);
201226
}
227+
} finally {
228+
_sharedMapLock.unlock();
202229
}
203230
}
204231

@@ -213,7 +240,8 @@ public void addAndResolveNonTypedSerializer(Class<?> rawType, JavaType fullType,
213240
SerializerProvider provider)
214241
throws JsonMappingException
215242
{
216-
synchronized (this) {
243+
try {
244+
_sharedMapLock.lock();
217245
Object ob1 = _sharedMap.put(new TypeKey(rawType, false), ser);
218246
Object ob2 = _sharedMap.put(new TypeKey(fullType, false), ser);
219247
if ((ob1 == null) || (ob2 == null)) {
@@ -222,6 +250,8 @@ public void addAndResolveNonTypedSerializer(Class<?> rawType, JavaType fullType,
222250
if (ser instanceof ResolvableSerializer) {
223251
((ResolvableSerializer) ser).resolve(provider);
224252
}
253+
} finally {
254+
_sharedMapLock.unlock();
225255
}
226256
}
227257

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,10 @@ protected JavaType _fromVariable(ClassStack context, TypeVariable<?> var, TypeBi
17581758
//
17591759
// No good way to reproduce but since this should not be on critical path, let's add
17601760
// syncing as it seems potentially necessary.
1761+
//
1762+
// 15-Mar-2024, oddbjornkvalsund: Not replacing this usage of 'synchronized' with an explicit lock as elsewhere.
1763+
// Assuming java.lang.reflect.TypeVariable.getBounds() does not do IO or other calls causing the thread to
1764+
// park and potentially pin to the platform thread.
17611765
synchronized (var) {
17621766
bounds = var.getBounds();
17631767
}

0 commit comments

Comments
 (0)