Skip to content

Commit 2f82f3c

Browse files
author
Fernando Blanch
committed
Remove the use of synchronized in the getBinder method of DefaultBinderFactory class for virtual-threads
The getBinder method in DefaultBinderFactory was made thread-safe using ReentrantLock. This commit ensures that the method is friendly for virtual threads to avoid blocking and pinning. The lock is acquired at the beginning of the method and released in a finally block to ensure it is always released, even if an exception occurs. Fixes gh-3004
1 parent 5d881b2 commit 2f82f3c

File tree

1 file changed

+32
-24
lines changed

1 file changed

+32
-24
lines changed

core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Map.Entry;
3131
import java.util.Properties;
3232
import java.util.Set;
33+
import java.util.concurrent.locks.ReentrantLock;
3334
import java.util.stream.Stream;
3435

3536
import org.apache.commons.logging.Log;
@@ -98,6 +99,8 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
9899

99100
private volatile String defaultBinder;
100101

102+
private static final ReentrantLock lock = new ReentrantLock();
103+
101104
public DefaultBinderFactory(Map<String, BinderConfiguration> binderConfigurations,
102105
BinderTypeRegistry binderTypeRegistry, BinderCustomizer binderCustomizer) {
103106
this.binderConfigurations = new HashMap<>(binderConfigurations);
@@ -142,34 +145,39 @@ public void destroy() {
142145

143146
@SuppressWarnings({ "unchecked", "rawtypes" })
144147
@Override
148+
public <T> Binder<T, ?, ?> getBinder(String name, Class<? extends T> bindingTargetType) {
149+
lock.lock();
150+
try {
151+
String binderName = StringUtils.hasText(name) ? name : this.defaultBinder;
145152

146-
public synchronized <T> Binder<T, ?, ?> getBinder(String name, Class<? extends T> bindingTargetType) {
147-
String binderName = StringUtils.hasText(name) ? name : this.defaultBinder;
148-
149-
Map<String, Binder> binders = this.context == null ? Collections.emptyMap() : this.context.getBeansOfType(Binder.class);
150-
Binder<T, ConsumerProperties, ProducerProperties> binder;
151-
if (StringUtils.hasText(binderName) && binders.containsKey(binderName)) {
152-
binder = (Binder<T, ConsumerProperties, ProducerProperties>) this.context.getBean(binderName);
153-
}
154-
else if (binders.size() == 1) {
155-
binder = binders.values().iterator().next();
156-
}
157-
else if (binders.size() > 1) {
158-
throw new IllegalStateException(
153+
Map<String, Binder> binders = this.context == null ? Collections.emptyMap() : this.context.getBeansOfType(Binder.class);
154+
Binder<T, ConsumerProperties, ProducerProperties> binder;
155+
if (StringUtils.hasText(binderName) && binders.containsKey(binderName)) {
156+
binder = (Binder<T, ConsumerProperties, ProducerProperties>) this.context.getBean(binderName);
157+
}
158+
else if (binders.size() == 1) {
159+
binder = binders.values().iterator().next();
160+
}
161+
else if (binders.size() > 1) {
162+
throw new IllegalStateException(
159163
"Multiple binders are available, however neither default nor "
160-
+ "per-destination binder name is provided. Available binders are "
161-
+ binders.keySet());
162-
}
163-
else {
164-
/*
165-
* This is the fallback to the old bootstrap that relies on spring.binders.
166-
*/
167-
binder = this.doGetBinder(binderName, bindingTargetType);
164+
+ "per-destination binder name is provided. Available binders are "
165+
+ binders.keySet());
166+
}
167+
else {
168+
/*
169+
* This is the fallback to the old bootstrap that relies on spring.binders.
170+
*/
171+
binder = this.doGetBinder(binderName, bindingTargetType);
172+
}
173+
if (this.binderCustomizer != null) {
174+
this.binderCustomizer.customize(binder, binderName);
175+
}
176+
return binder;
168177
}
169-
if (this.binderCustomizer != null) {
170-
this.binderCustomizer.customize(binder, binderName);
178+
finally {
179+
lock.unlock();
171180
}
172-
return binder;
173181
}
174182

175183
private <T> Binder<T, ConsumerProperties, ProducerProperties> doGetBinder(String name, Class<? extends T> bindingTargetType) {

0 commit comments

Comments
 (0)