Change "synchronized" to reentrant lock for virtual-threads

Fix checkstyles before merge

Code cleanup

Double-Checked Locking Optimization was used to avoid unnecessary locking overhead.
This commit is contained in:
Ömer Çelik
2024-10-04 23:03:56 +03:00
committed by Oleg Zhurakousky
parent 7a5e5d0541
commit cbfd3aa995
7 changed files with 216 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2022 the original author or authors.
* Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.cloud.stream.binding;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -43,6 +44,7 @@ import org.springframework.util.Assert;
* @author Ilayaperumal Gopinathan
* @author Oleg Zhurakousky
* @author Soby Chacko
* @author Omer Celik
*/
public class BindableProxyFactory extends AbstractBindableProxyFactory
implements MethodInterceptor, FactoryBean<Object>, InitializingBean, BeanFactoryAware {
@@ -55,21 +57,25 @@ public class BindableProxyFactory extends AbstractBindableProxyFactory
protected BeanFactory beanFactory;
private final ReentrantLock lock = new ReentrantLock();
public BindableProxyFactory(Class<?> type) {
super(type);
this.type = type;
}
@Override
public synchronized Object invoke(MethodInvocation invocation) {
Method method = invocation.getMethod();
public Object invoke(MethodInvocation invocation) {
try {
this.lock.lock();
Method method = invocation.getMethod();
// try to use cached target
Object boundTarget = this.targetCache.get(method);
if (boundTarget != null) {
return boundTarget;
// try to use cached target
return this.targetCache.get(method);
}
finally {
this.lock.unlock();
}
return null;
}
public void replaceInputChannel(String originalChannelName, String newChannelName, SubscribableChannel messageChannel) {
@@ -97,11 +103,22 @@ public class BindableProxyFactory extends AbstractBindableProxyFactory
"'bindingTargetFactories' cannot be empty");
}
/**
* Double-Checked Locking Optimization was used to avoid unnecessary locking overhead.
*/
@Override
public synchronized Object getObject() {
public Object getObject() {
if (this.proxy == null && this.type != null) {
ProxyFactory factory = new ProxyFactory(this.type, this);
this.proxy = factory.getProxy();
try {
this.lock.lock();
if (this.proxy == null && this.type != null) {
ProxyFactory factory = new ProxyFactory(this.type, this);
this.proxy = factory.getProxy();
}
}
finally {
this.lock.unlock();
}
}
return this.proxy;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -63,6 +64,7 @@ import org.springframework.validation.DataBinder;
* @author Chris Bono
* @author Artem Bilan
* @author Byungjun You
* @author Omer Celik
*/
public class BindingService {
@@ -451,35 +453,49 @@ public class BindingService {
private final String bindingName;
private final Object consumerOrProducerproperties;
private final Object consumerOrProducerProperties;
private final boolean isInput;
final ObjectMapper objectMapper;
LateBinding(String bindingName, String error, Object consumerOrProducerproperties, boolean isInput, ObjectMapper objectMapper) {
private final ReentrantLock lock = new ReentrantLock();
LateBinding(String bindingName, String error, Object consumerOrProducerProperties, boolean isInput, ObjectMapper objectMapper) {
super();
this.error = error;
this.bindingName = bindingName;
this.consumerOrProducerproperties = consumerOrProducerproperties;
this.consumerOrProducerProperties = consumerOrProducerProperties;
this.isInput = isInput;
this.objectMapper = objectMapper;
}
public synchronized void setDelegate(Binding<T> delegate) {
if (this.unbound) {
delegate.unbind();
public void setDelegate(Binding<T> delegate) {
try {
this.lock.lock();
if (this.unbound) {
delegate.unbind();
}
else {
this.delegate = delegate;
}
}
else {
this.delegate = delegate;
finally {
this.lock.unlock();
}
}
@Override
public synchronized void unbind() {
this.unbound = true;
if (this.delegate != null) {
this.delegate.unbind();
public void unbind() {
try {
this.lock.lock();
this.unbound = true;
if (this.delegate != null) {
this.delegate.unbind();
}
}
finally {
this.lock.unlock();
}
}
@@ -507,8 +523,8 @@ public class BindingService {
public Map<String, Object> getExtendedInfo() {
Map<String, Object> extendedInfo = new LinkedHashMap<>();
extendedInfo.put("bindingDestination", this.getBindingName());
extendedInfo.put(consumerOrProducerproperties.getClass().getSimpleName(),
this.objectMapper.convertValue(consumerOrProducerproperties, Map.class));
extendedInfo.put(consumerOrProducerProperties.getClass().getSimpleName(),
this.objectMapper.convertValue(consumerOrProducerProperties, Map.class));
return extendedInfo;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.cloud.stream.binder.Binding;
@@ -29,6 +30,7 @@ import org.springframework.cloud.stream.binder.Binding;
*
* @author Ilayaperumal Gopinathan
* @author Oleg Zhurakousky
* @author Omer Celik
*/
public final class DynamicDestinationsBindable implements Bindable {
@@ -37,21 +39,41 @@ public final class DynamicDestinationsBindable implements Bindable {
*/
private final Map<String, Binding<?>> outputBindings = new HashMap<>();
public synchronized void addOutputBinding(String name, Binding<?> binding) {
this.outputBindings.put(name, binding);
}
private static final ReentrantLock outputBindingsLock = new ReentrantLock();
@Override
public synchronized Set<String> getOutputs() {
return Collections.unmodifiableSet(this.outputBindings.keySet());
}
@Override
public synchronized void unbindOutputs(BindingService adapter) {
for (Map.Entry<String, Binding<?>> entry : this.outputBindings.entrySet()) {
entry.getValue().unbind();
public void addOutputBinding(String name, Binding<?> binding) {
try {
outputBindingsLock.lock();
this.outputBindings.put(name, binding);
}
finally {
outputBindingsLock.unlock();
}
}
@Override
public Set<String> getOutputs() {
try {
outputBindingsLock.lock();
return Collections.unmodifiableSet(this.outputBindings.keySet());
}
finally {
outputBindingsLock.unlock();
}
}
@Override
public void unbindOutputs(BindingService adapter) {
try {
outputBindingsLock.lock();
for (Map.Entry<String, Binding<?>> entry : this.outputBindings.entrySet()) {
entry.getValue().unbind();
}
this.outputBindings.clear();
}
finally {
outputBindingsLock.unlock();
}
this.outputBindings.clear();
}
}