From c4f66b776fd533d5a3fc99b8e3a0d679887bb482 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 12 Apr 2025 06:00:18 +0200 Subject: [PATCH] Use single volatile field for indicating pre-instantiation phase See gh-34729 --- .../support/DefaultListableBeanFactory.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index e6c00e9e3c2..44f24cc912d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -218,8 +218,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto /** Whether bean definition metadata may be cached for all beans. */ private volatile boolean configurationFrozen; - private volatile boolean preInstantiationPhase; - + /** Name prefix of main thread: only set during pre-instantiation phase. */ @Nullable private volatile String mainThreadPrefix; @@ -1066,11 +1065,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override @Nullable protected Boolean isCurrentThreadAllowedToHoldSingletonLock() { - if (this.preInstantiationPhase) { + String mainThreadPrefix = this.mainThreadPrefix; + if (this.mainThreadPrefix != null) { // We only differentiate in the preInstantiateSingletons phase. + PreInstantiation preInstantiation = this.preInstantiationThread.get(); if (preInstantiation != null) { - // A Spring-managed thread: + // A Spring-managed bootstrap thread: // MAIN is allowed to lock (true) or even forced to lock (null), // BACKGROUND is never allowed to lock (false). return switch (preInstantiation) { @@ -1078,14 +1079,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto case BACKGROUND -> false; }; } - if (Boolean.FALSE.equals(this.strictLocking) || - (this.strictLocking == null && !getThreadNamePrefix().equals(this.mainThreadPrefix))) { - // An unmanaged thread (assumed to be application-internal) with lenient locking, - // and not part of the same thread pool that provided the main bootstrap thread - // (excluding scenarios where we are hit by multiple external bootstrap threads). + + // Not a Spring-managed bootstrap thread... + if (Boolean.FALSE.equals(this.strictLocking)) { + // Explicitly configured to use lenient locking wherever possible. return true; } + else if (this.strictLocking == null) { + // No explicit locking configuration -> infer appropriate locking. + if (mainThreadPrefix != null && !getThreadNamePrefix().equals(mainThreadPrefix)) { + // An unmanaged thread (assumed to be application-internal) with lenient locking, + // and not part of the same thread pool that provided the main bootstrap thread + // (excluding scenarios where we are hit by multiple external bootstrap threads). + return true; + } + } } + // Traditional behavior: forced to always hold a full lock. return null; } @@ -1103,7 +1113,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto // Trigger initialization of all non-lazy singleton beans... List> futures = new ArrayList<>(); - this.preInstantiationPhase = true; this.preInstantiationThread.set(PreInstantiation.MAIN); this.mainThreadPrefix = getThreadNamePrefix(); try { @@ -1120,7 +1129,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto finally { this.mainThreadPrefix = null; this.preInstantiationThread.remove(); - this.preInstantiationPhase = false; } if (!futures.isEmpty()) {