How to Answer Bean Thread‑Safety Questions from an Architecture‑Responsibility Perspective
The article breaks down Bean thread‑safety into container‑level creation safety and business‑level usage safety, explains Spring's four concurrency strategies, details the implementation of Singleton, Prototype, Request and Session scopes, compares them with other DI frameworks, and argues why Spring's division of responsibilities is appropriate.
When interviewers ask about Bean thread safety, the problem can be split into two layers: the container layer, which must ensure that Bean creation and retrieval are thread‑safe, and the business layer, where developers must guarantee that mutable fields are accessed safely.
Four generic concurrency strategies
Mutual exclusion synchronization – only one thread can enter the critical section; suitable for shared mutable state; incurs lock contention.
Non‑blocking synchronization – uses CAS and retries on conflict; fits low‑contention counters or flags; high contention leads to CPU‑intensive spinning.
Thread isolation – each thread holds an independent copy; ideal when each thread needs its own state; memory usage grows with thread count.
Stateless design – objects hold no mutable shared state; works for pure computation or delegation classes; not applicable when state must be preserved.
Spring’s approach: container manages lifecycle, business manages concurrency
Singleton Bean creation
Spring stores Singleton instances in DefaultSingletonBeanRegistry, which maintains three maps: singletonObjects (fully initialized beans), singletonFactories (factories for beans in creation, used for circular references), and earlySingletonObjects (early references). The creation path uses a synchronized block on singletonObjects to coordinate updates across the three maps, guaranteeing that a Bean is created only once and never returned half‑constructed. Read‑only access usually bypasses the lock, providing a read‑write separation optimization.
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = singletonFactory.getObject();
addSingleton(beanName, singletonObject);
}
}This answers the first layer: Spring guarantees thread‑safe creation of Singleton Beans.
Prototype Bean: thread isolation
Prototype‑scoped Beans are created anew on each getBean call, eliminating shared instances. Spring tracks the creation of Prototype Beans with a ThreadLocal, ensuring each thread has its own creation context without any locking.
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");Request and Session scopes: web‑container thread model
Request‑scoped Beans have one instance per HTTP request, while Session‑scoped Beans have one per user session. Spring relies on the servlet container’s thread model: each request runs in its own thread, and RequestContextHolder binds the current RequestAttributes to a ThreadLocal. Consequently, Request‑scoped Beans are naturally thread‑safe. Session‑scoped Beans depend on the servlet container’s thread‑safe HttpSession; Spring’s Scope contract requires implementations to be thread‑safe.
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");Mapping scopes to the four strategies
Singleton creation uses mutual‑exclusion synchronization; usage is left to developers.
Prototype uses thread isolation, creating a fresh instance per request.
Request scope also uses thread isolation, but at the request level.
Session scope relies on the servlet container’s mutex‑based safety.
Spring’s design consistently prefers avoiding shared state when possible (Prototype, Request) and, when sharing is unavoidable (Singleton), limits its responsibility to safe creation only.
Is Spring’s solution the best choice?
The discussion is limited to container‑level thread safety, not to general concurrency mechanisms. Adding a read/write lock to getBean would not solve business‑level data races because the lock would only protect the reference retrieval, not subsequent field accesses, and would introduce unnecessary synchronization overhead.
Therefore, Spring’s separation—container guarantees creation safety, business code handles usage safety—is a reasonable trade‑off.
Changes in newer Spring versions
Spring Framework 6.0 (used by Spring Boot 3) retains the same strategy; the only notable change is Spring Boot’s default disabling of circular references from version 2.6, which reduces the use of earlySingletonObjects but does not alter the thread‑safety approach.
Other DI frameworks
Google Guice, CDI (Weld), and Micronaut follow the same pattern: the container ensures thread‑safe creation of Singleton beans (often using synchronized blocks or double‑checked locking) while leaving business‑level concurrency to the developer.
Conclusion
Bean thread safety illustrates a broader architectural principle: clear responsibility boundaries determine whether a problem can be cleanly solved. Spring, Guice, CDI, and Micronaut all draw the line between lifecycle management and concurrent data handling, showing that the pattern is dictated by the role of a dependency‑injection container rather than by any single vendor’s preference.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
