When to Use volatile with ConcurrentHashMap and Spring Bean Thread Safety

A ConcurrentHashMap is internally thread‑safe, so a volatile declaration is only required when its reference may be reassigned (or the field is final), while Spring singleton beans with mutable fields are not thread‑safe and should be made stateless, prototype‑scoped, or synchronized for composite operations.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
When to Use volatile with ConcurrentHashMap and Spring Bean Thread Safety

In a multi‑threaded environment, the interview question asks whether a ConcurrentHashMap (CHM) should be declared volatile to ensure thread safety.

CHM itself provides thread‑safe operations, but its safety only covers the internal methods. If the reference to the CHM never changes, no volatile is needed.

Example of immutable reference:

private static final ConcurrentHashMap<String, String> chm = new ConcurrentHashMap<>();

If the CHM reference can be reassigned, volatile (or final) is required so that other threads see the new instance.

private volatile ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();
public void updateCache() {
    ConcurrentHashMap<String, String> newCache = new ConcurrentHashMap<>();
    // fill newCache ...
    cache = newCache;
}

The same reasoning applies to Spring beans. A singleton bean with mutable state (e.g., an int field) is not thread‑safe; a prototype bean or a stateless singleton is.

@Controller
public class TestController {
    private int num = 0;
    @RequestMapping("/test")
    public void test() { System.out.println(++num); }
    @RequestMapping("/test1")
    public void test1() { System.out.println(++num); }
}

Changing the bean scope to prototype makes each request get a new instance, eliminating shared mutable state.

When a CHM is stored in a singleton controller, the map itself is thread‑safe, but reassigning the map reference without volatile can cause visibility issues.

@RestController
public class TestController {
    private ConcurrentHashMap chm = new ConcurrentHashMap();
    @RequestMapping("/test")
    public void test() { chm.put("1", "1"); }
    @RequestMapping("/test1")
    public void test1() { chm.put("2", "2"); }
}

Solutions include adding volatile, declaring the field final, or using prototype scope.

Composite operations on CHM (e.g., get‑then‑put) are not atomic; external synchronization may be required, as shown in Spring’s SimpleAliasRegistry implementation.

Similarly, Redis get‑set sequences are not atomic, which is why commands like INCR exist.

The article also contains a personal anecdote about playing billiards, which is unrelated to the technical discussion.

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 safetyConcurrentHashMapvolatile
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

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.