Description
The container injection (DI) mechanism shows high contention when injecting Scope.SINGLETON instances under high stress load in an enterprise application using Struts 2.5.20.
The symptom is that UI response times vary from a few dozens of milliseconds up to a full second without any obvious reason.
Profiling the app while under load stress using https://github.com/jvm-profiling-tools/async-profiler (using the lock mode and --reverse option to aggregate on the various contention code locations) shows the following picture:
Analyzing the code path shows the highly contended code:
SINGLETON { @Override <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, final InternalFactory<? extends T> factory) { return new InternalFactory<T>() { T instance; public T create(InternalContext context) { synchronized (context.getContainer()) { if (instance == null) { instance = InitializableFactory.wrapIfNeeded(factory).create(context); } return instance; } } ... },
The fully synchronised section for accessing the singleton instance is the core issue here.
Using the double-null-check-on-volatile pattern (which I dislike but is reliable since Java 1.5 with the volatile keyword) entirely removes the contention issue and response times become much more stable.