Ensuring Thread Safety for Spring Singleton Beans: Problems and Solutions
This article explains why Spring singleton beans can be unsafe in concurrent scenarios, demonstrates the issue with a controller example, and presents multiple solutions including changing bean scope, using ThreadLocal, avoiding member variables, employing concurrent collections, and leveraging distributed caches.
Spring beans are singleton by default, which can cause concurrency issues when member variables are used in Controllers because multiple requests share the same instance.
Example code shows a singleton controller with an int field that increments on each request, demonstrating unsafe behavior.
@Controller
public class HomeController {
private int i;
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
return ++i;
}
}To achieve stateless handling of massive HTTP requests, several solutions are presented:
1. Change bean scope to prototype or request
Annotate the controller with @Scope("prototype") or @Scope("request") (or on non‑web components use @Scope("prototype") ), which creates a new instance per request but increases resource consumption.
2. Use ThreadLocal for thread isolation
Wrap the member variable in a ThreadLocal to keep a separate value per thread, as shown below, and log the thread name and value.
@Controller
public class HomeController {
private ThreadLocal
i = new ThreadLocal<>();
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
if (i.get() == null) {
i.set(0);
}
i.set(i.get() + 1);
log.info("{} -> {}", Thread.currentThread().getName(), i.get());
return i.get();
}
}Log output shows each thread maintains its own counter, but the approach still does not guarantee overall concurrency safety.
3. Avoid member variables
Prefer using method‑local variables instead of fields, which is the simplest and recommended way.
@Controller
public class HomeController {
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
int i = 0;
// TODO business code
return ++i;
}
}4. Use concurrent collections such as ConcurrentHashMap when a shared mutable state is required.
5. For distributed systems, store shared state in external caches like Redis.
Finally, the article lists the five Spring bean scopes (singleton, prototype, request, session, global session) and briefly describes each.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.