@@ -218,8 +218,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
218218 /** Whether bean definition metadata may be cached for all beans. */
219219 private volatile boolean configurationFrozen ;
220220
221- private volatile boolean preInstantiationPhase ;
222-
221+ /** Name prefix of main thread: only set during pre-instantiation phase. */
223222 @ Nullable
224223 private volatile String mainThreadPrefix ;
225224
@@ -1066,26 +1065,37 @@ protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName
10661065 @ Override
10671066 @ Nullable
10681067 protected Boolean isCurrentThreadAllowedToHoldSingletonLock () {
1069- if (this .preInstantiationPhase ) {
1068+ String mainThreadPrefix = this .mainThreadPrefix ;
1069+ if (this .mainThreadPrefix != null ) {
10701070 // We only differentiate in the preInstantiateSingletons phase.
1071+
10711072 PreInstantiation preInstantiation = this .preInstantiationThread .get ();
10721073 if (preInstantiation != null ) {
1073- // A Spring-managed thread:
1074+ // A Spring-managed bootstrap thread:
10741075 // MAIN is allowed to lock (true) or even forced to lock (null),
10751076 // BACKGROUND is never allowed to lock (false).
10761077 return switch (preInstantiation ) {
10771078 case MAIN -> (Boolean .TRUE .equals (this .strictLocking ) ? null : true );
10781079 case BACKGROUND -> false ;
10791080 };
10801081 }
1081- if (Boolean .FALSE .equals (this .strictLocking ) ||
1082- (this .strictLocking == null && !getThreadNamePrefix ().equals (this .mainThreadPrefix ))) {
1083- // An unmanaged thread (assumed to be application-internal) with lenient locking,
1084- // and not part of the same thread pool that provided the main bootstrap thread
1085- // (excluding scenarios where we are hit by multiple external bootstrap threads).
1082+
1083+ // Not a Spring-managed bootstrap thread...
1084+ if (Boolean .FALSE .equals (this .strictLocking )) {
1085+ // Explicitly configured to use lenient locking wherever possible.
10861086 return true ;
10871087 }
1088+ else if (this .strictLocking == null ) {
1089+ // No explicit locking configuration -> infer appropriate locking.
1090+ if (mainThreadPrefix != null && !getThreadNamePrefix ().equals (mainThreadPrefix )) {
1091+ // An unmanaged thread (assumed to be application-internal) with lenient locking,
1092+ // and not part of the same thread pool that provided the main bootstrap thread
1093+ // (excluding scenarios where we are hit by multiple external bootstrap threads).
1094+ return true ;
1095+ }
1096+ }
10881097 }
1098+
10891099 // Traditional behavior: forced to always hold a full lock.
10901100 return null ;
10911101 }
@@ -1103,7 +1113,6 @@ public void preInstantiateSingletons() throws BeansException {
11031113 // Trigger initialization of all non-lazy singleton beans...
11041114 List <CompletableFuture <?>> futures = new ArrayList <>();
11051115
1106- this .preInstantiationPhase = true ;
11071116 this .preInstantiationThread .set (PreInstantiation .MAIN );
11081117 this .mainThreadPrefix = getThreadNamePrefix ();
11091118 try {
@@ -1120,7 +1129,6 @@ public void preInstantiateSingletons() throws BeansException {
11201129 finally {
11211130 this .mainThreadPrefix = null ;
11221131 this .preInstantiationThread .remove ();
1123- this .preInstantiationPhase = false ;
11241132 }
11251133
11261134 if (!futures .isEmpty ()) {
0 commit comments