@@ -99,9 +99,6 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
99
99
/** Names of beans currently excluded from in creation checks. */
100
100
private final Set <String > inCreationCheckExclusions = ConcurrentHashMap .newKeySet (16 );
101
101
102
- @ Nullable
103
- private volatile Thread singletonCreationThread ;
104
-
105
102
/** Flag that indicates whether we're currently within destroySingletons. */
106
103
private volatile boolean singletonsCurrentlyInDestruction = false ;
107
104
@@ -242,37 +239,33 @@ protected Object getSingleton(String beanName, boolean allowEarlyReference) {
242
239
public Object getSingleton (String beanName , ObjectFactory <?> singletonFactory ) {
243
240
Assert .notNull (beanName , "Bean name must not be null" );
244
241
245
- boolean acquireLock = isCurrentThreadAllowedToHoldSingletonLock ();
242
+ Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock ();
243
+ boolean acquireLock = !Boolean .FALSE .equals (lockFlag );
246
244
boolean locked = (acquireLock && this .singletonLock .tryLock ());
247
245
try {
248
246
Object singletonObject = this .singletonObjects .get (beanName );
249
247
if (singletonObject == null ) {
250
- if (acquireLock ) {
251
- if (locked ) {
252
- this .singletonCreationThread = Thread .currentThread ();
248
+ if (acquireLock && !locked ) {
249
+ if (Boolean .TRUE .equals (lockFlag )) {
250
+ // Another thread is busy in a singleton factory callback, potentially blocked.
251
+ // Fallback as of 6.2: process given singleton bean outside of singleton lock.
252
+ // Thread-safe exposure is still guaranteed, there is just a risk of collisions
253
+ // when triggering creation of other beans as dependencies of the current bean.
254
+ if (logger .isInfoEnabled ()) {
255
+ logger .info ("Creating singleton bean '" + beanName + "' in thread \" " +
256
+ Thread .currentThread ().getName () + "\" while other thread holds " +
257
+ "singleton lock for other beans " + this .singletonsCurrentlyInCreation );
258
+ }
253
259
}
254
260
else {
255
- Thread threadWithLock = this .singletonCreationThread ;
256
- if (threadWithLock != null ) {
257
- // Another thread is busy in a singleton factory callback, potentially blocked.
258
- // Fallback as of 6.2: process given singleton bean outside of singleton lock.
259
- // Thread-safe exposure is still guaranteed, there is just a risk of collisions
260
- // when triggering creation of other beans as dependencies of the current bean.
261
- if (logger .isInfoEnabled ()) {
262
- logger .info ("Creating singleton bean '" + beanName + "' in thread \" " +
263
- Thread .currentThread ().getName () + "\" while thread \" " + threadWithLock .getName () +
264
- "\" holds singleton lock for other beans " + this .singletonsCurrentlyInCreation );
265
- }
266
- }
267
- else {
268
- // Singleton lock currently held by some other registration method -> wait.
269
- this .singletonLock .lock ();
270
- locked = true ;
271
- // Singleton object might have possibly appeared in the meantime.
272
- singletonObject = this .singletonObjects .get (beanName );
273
- if (singletonObject != null ) {
274
- return singletonObject ;
275
- }
261
+ // No specific locking indication (outside a coordinated bootstrap) and
262
+ // singleton lock currently held by some other creation method -> wait.
263
+ this .singletonLock .lock ();
264
+ locked = true ;
265
+ // Singleton object might have possibly appeared in the meantime.
266
+ singletonObject = this .singletonObjects .get (beanName );
267
+ if (singletonObject != null ) {
268
+ return singletonObject ;
276
269
}
277
270
}
278
271
}
@@ -291,7 +284,6 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
291
284
if (recordSuppressedExceptions ) {
292
285
this .suppressedExceptions = new LinkedHashSet <>();
293
286
}
294
- this .singletonCreationThread = Thread .currentThread ();
295
287
try {
296
288
singletonObject = singletonFactory .getObject ();
297
289
newSingleton = true ;
@@ -313,7 +305,6 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
313
305
throw ex ;
314
306
}
315
307
finally {
316
- this .singletonCreationThread = null ;
317
308
if (recordSuppressedExceptions ) {
318
309
this .suppressedExceptions = null ;
319
310
}
@@ -336,10 +327,15 @@ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
336
327
* Determine whether the current thread is allowed to hold the singleton lock.
337
328
* <p>By default, any thread may acquire and hold the singleton lock, except
338
329
* background threads from {@link DefaultListableBeanFactory#setBootstrapExecutor}.
330
+ * @return {@code false} if the current thread is explicitly not allowed to hold
331
+ * the lock, {@code true} if it is explicitly allowed to hold the lock but also
332
+ * accepts lenient fallback behavior, or {@code null} if there is no specific
333
+ * indication (traditional behavior: always holding a full lock)
339
334
* @since 6.2
340
335
*/
341
- protected boolean isCurrentThreadAllowedToHoldSingletonLock () {
342
- return true ;
336
+ @ Nullable
337
+ protected Boolean isCurrentThreadAllowedToHoldSingletonLock () {
338
+ return null ;
343
339
}
344
340
345
341
/**
0 commit comments