@@ -211,9 +211,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
211
211
/** Whether bean definition metadata may be cached for all beans. */
212
212
private volatile boolean configurationFrozen ;
213
213
214
- private volatile boolean preInstantiationPhase ;
215
-
216
- private @ Nullable volatile String mainThreadPrefix ;
214
+ /** Name prefix of main thread: only set during pre-instantiation phase. */
215
+ private volatile @ Nullable String mainThreadPrefix ;
217
216
218
217
private final NamedThreadLocal <PreInstantiation > preInstantiationThread =
219
218
new NamedThreadLocal <>("Pre-instantiation thread marker" );
@@ -1048,26 +1047,37 @@ protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName
1048
1047
1049
1048
@ Override
1050
1049
protected @ Nullable Boolean isCurrentThreadAllowedToHoldSingletonLock () {
1051
- if (this .preInstantiationPhase ) {
1050
+ String mainThreadPrefix = this .mainThreadPrefix ;
1051
+ if (this .mainThreadPrefix != null ) {
1052
1052
// We only differentiate in the preInstantiateSingletons phase.
1053
+
1053
1054
PreInstantiation preInstantiation = this .preInstantiationThread .get ();
1054
1055
if (preInstantiation != null ) {
1055
- // A Spring-managed thread:
1056
+ // A Spring-managed bootstrap thread:
1056
1057
// MAIN is allowed to lock (true) or even forced to lock (null),
1057
1058
// BACKGROUND is never allowed to lock (false).
1058
1059
return switch (preInstantiation ) {
1059
1060
case MAIN -> (Boolean .TRUE .equals (this .strictLocking ) ? null : true );
1060
1061
case BACKGROUND -> false ;
1061
1062
};
1062
1063
}
1063
- if (Boolean .FALSE .equals (this .strictLocking ) ||
1064
- (this .strictLocking == null && !getThreadNamePrefix ().equals (this .mainThreadPrefix ))) {
1065
- // An unmanaged thread (assumed to be application-internal) with lenient locking,
1066
- // and not part of the same thread pool that provided the main bootstrap thread
1067
- // (excluding scenarios where we are hit by multiple external bootstrap threads).
1064
+
1065
+ // Not a Spring-managed bootstrap thread...
1066
+ if (Boolean .FALSE .equals (this .strictLocking )) {
1067
+ // Explicitly configured to use lenient locking wherever possible.
1068
1068
return true ;
1069
1069
}
1070
+ else if (this .strictLocking == null ) {
1071
+ // No explicit locking configuration -> infer appropriate locking.
1072
+ if (mainThreadPrefix != null && !getThreadNamePrefix ().equals (mainThreadPrefix )) {
1073
+ // An unmanaged thread (assumed to be application-internal) with lenient locking,
1074
+ // and not part of the same thread pool that provided the main bootstrap thread
1075
+ // (excluding scenarios where we are hit by multiple external bootstrap threads).
1076
+ return true ;
1077
+ }
1078
+ }
1070
1079
}
1080
+
1071
1081
// Traditional behavior: forced to always hold a full lock.
1072
1082
return null ;
1073
1083
}
@@ -1085,7 +1095,6 @@ public void preInstantiateSingletons() throws BeansException {
1085
1095
// Trigger initialization of all non-lazy singleton beans...
1086
1096
List <CompletableFuture <?>> futures = new ArrayList <>();
1087
1097
1088
- this .preInstantiationPhase = true ;
1089
1098
this .preInstantiationThread .set (PreInstantiation .MAIN );
1090
1099
this .mainThreadPrefix = getThreadNamePrefix ();
1091
1100
try {
@@ -1102,7 +1111,6 @@ public void preInstantiateSingletons() throws BeansException {
1102
1111
finally {
1103
1112
this .mainThreadPrefix = null ;
1104
1113
this .preInstantiationThread .remove ();
1105
- this .preInstantiationPhase = false ;
1106
1114
}
1107
1115
1108
1116
if (!futures .isEmpty ()) {
0 commit comments