Why Spring Controllers Are Not Thread‑Safe and How to Fix Them

Spring MVC controllers are singleton by default, which can cause thread‑unsafe behavior when using non‑static member variables; this article demonstrates the issue with example endpoints, shows how prototype scope resolves it, and outlines best practices such as avoiding stateful fields or using ThreadLocal.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Spring Controllers Are Not Thread‑Safe and How to Fix Them
Controllers are singleton by default; do not use non‑static member variables, otherwise data logic becomes chaotic. Because they are singletons they are not thread‑safe.

We first verify the problem with a simple controller:

package com.riemann.springbootdemo.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author riemann
 * @date 2019/07/29 22:56
 */
@Controller
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {
        System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {
        System.out.println(++num);
    }
}

Calling http://localhost:8080/testScope prints 1. Calling http://localhost:8080/testScope2 prints 2, showing different values and thus thread‑unsafe behavior.

Adding prototype scope to the controller

We modify the controller to use @Scope("prototype"):

package com.riemann.springbootdemo.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author riemann
 * @date 2019/07/29 22:56
 */
@Controller
@Scope("prototype")
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {
        System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {
        System.out.println(++num);
    }
}

Now both /testScope and /testScope2 return 1, confirming that each request gets a separate instance.

Singleton beans are unsafe for controllers because their fields can be reused across threads.

Solution

Do not define member variables in a controller.

If a non‑static field is unavoidable, annotate the controller with @Scope("prototype") to make it prototype scoped.

Use ThreadLocal variables inside the controller when thread‑local state is required.

Supplementary Explanation

Spring bean scopes include five types:

singleton : one instance per Spring container; created eagerly unless lazy-init is used.

prototype : a new instance is created each time the bean is requested; Spring does not manage its full lifecycle after creation.

request : (web only) a new instance per HTTP request, with Spring continuing to manage it.

session : (web only) a new instance per HTTP session.

globalSession : (web only) a global session scope, similar to the servlet application scope.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaspringthread safetyControllerSingletonprototypeBean Scope
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.