Mastering Maps in Programming: Real-World Applications and Concurrency Explained
A comprehensive guide to understanding maps, their challenges, and when to choose HashMap or ConcurrentHashMap.
The motivation behind this blog post comes from a recent challenge I encountered while working on the LeetCode problem Find Common Characters.
Interestingly, I’ve faced a similar issue before in real-world code but didn’t explore it deeply at the time—I just applied a quick fix and moved on. This time, I decided to dive deeper and document my findings. 🙏
Although I aimed to keep this post concise, I couldn’t help but delve into the topic a bit more than planned. Here’s a quick breakdown of what you’ll find in this article:
Why Do We Use Maps/Tables in programming?
Real-World Implications Of Maps
Concurrency / Multi-Threading and Maps
The Challenge: Concurrent Modifications in Java Collections
Actually, Why ConcurrentHashMap Works?
K, But When Does HashMap Fail Then?
Real-World Example: Why ConcurrentHashMap is Necessary
Choosing Between HashMap and ConcurrentHashMap
What Have We Learned?
Takeaways
Why Do We Use Maps/Tables in programming?
depending on the language, you might see this data structure defined as a map, dict, dictionary, table .. all of these are basically the same.
quick intro: they are a key-value data structure!
If you can’t answer this question, well, you most probably have big gaps in the fundamentals of programming.
So visit a programming doctor and tell them I sent you👇
They will help you fix those gaps, mentor you along the way and help you become at least 2X better than you are at the moment. No matter the level you’re at!
After visiting the doc, let’s actually see why do we need this DS in our lives 📌
Each record in a map is a key-value pair
Fast Lookups: Finding a value by it’s key is constant time operation, O(1) ( read more about the time complexity & what does it mean here). For example: quickly finding a user’s profile details using their unique ID
Efficient Data Organization: they support updates without traversal of the whole object.
Dynamic Sizing: unlike arrays, maps can efficiently scale in size.
Real-World Implications Of Maps
1. Caching Mechanisms
Maps are the backbone of caching systems, enabling fast data retrieval for frequently accessed information. For example, Redis, a popular in-memory data store, uses a map-like structure to store key-value pairs for quick access.
Leaving Redis aside, a lot of companies use in-memory caches for faster lookups & like mentioned above, Maps have this unique & important feature!
// an in-memory cache can be set as simply as that:
Map<Integer, String> cache = new HashMap<>();
2. Database Indexing
Maps are fundamental to database indexing, where keys represent indexed fields for rapid lookups. For instance, a SQL database might use a B-Tree or Hash Index internally—both of which rely on the concept of mapping keys to locations in data.
this blog post talks extensively about how DBs use maps to set indexes 📌
3. Load Balancing
Load balancers often use maps to route incoming requests to the appropriate server based on hashing. For example, a consistent hashing algorithm might use a HashMap
to maintain mappings between server nodes and hashed keys.
here you will find different mapping techniques for load balancers!
4. Real-Time Analytics
Applications like LinkedIn and Twitter utilize maps to count events such as likes, shares, or comments in real time. Using a specific type of Map 🤫 , they ensure that these counts are accurate even in high-concurrency environments
5. Google Calendar
they use HashMaps for fast lookups. Someone actually used this idea in their own project. Here is the problem statement:
you can see the solution, utilizing HashMap, in this LinkedIn post! 👈
6. Can you think of other use-cases?
Share them in the comments for everyone to see! 🙏
Concurrency / Multi-Threading and Maps
When working in multi-threaded environments (again, visit the doc 👆 if you don’t know what that is), there is this concept of concurrency & how it can cause some major issues if not handled correctly.
How to handle it correctly is a pretty major topic in the computer science field and there are books that talk solely about concurrency, especially in a multi-threaded languages like Java.
I will try to give a brief overview in some of my next blog- posts 🙏
just for reference, you can see here - 184 books on concurrency are available on Amazon only 😆
That said, keeping our minds on Maps, how are they related to concurrency? In Java, there are different types of Maps. And understanding the importance of maps in programming provides context for why selecting the appropriate type of map (e.g., HashMap
or ConcurrentHashMap
) is crucial in specific scenarios.
And that’s why we will be focusing on when and why to use one over the other 👇
The Challenge: Concurrent Modifications in Java Collections
When working with Java collections, handling concurrent modifications can be tricky. One common pitfall is encountering a ConcurrentModificationException
🚨when iterating over a HashMap
while modifying it.
Today I actually got this exact exception in one of my solutions on Leetcode. As I mentioned above, this was the ‘Find Common Characters’ problem. I used a blank HashMap to solve it and boom 💣
👉 This exception often arises in multi-threaded environments or scenarios where updates and reads happen simultaneously.
⚠️ I do wanna mention that
ConcurrentModificationException
can also occur in single-threaded environments. In single-threaded envs, this exception can happen when you're looping with an iterator and you make structural changes to the structure but not via the iterator.Please check the official documentation for further reading on ConcurrentModificationException
And why did it happen here?
In Java, iterating over a HashMap
using entrySet()
creates an iterator.
If the map is structurally modified during this iteration (e.g., by adding or removing elements, like I do here), the iterator detects the change and throws a ConcurrentModificationException
.
How to fix it?
To overcome this, Java offers ConcurrentHashMap
, a thread-safe alternative that prevents such exceptions and ensures consistent behavior.
📒 Note: I know this problem has different approaches to it, that can also prevent this error from happening - using dynamic or static arrays.. But the point I am trying to make is on maps and concurrency, not on the fix for problem #1002 📌
Actually, Why ConcurrentHashMap Works?
Thread-Safe Iteration
Unlike HashMap
, ConcurrentHashMap
allows modifications (like put
or remove
) during iteration without throwing ConcurrentModificationException
. This is crucial in concurrent environments where multiple threads access and modify the map.
Internal Mechanism
Segmented Locking:
ConcurrentHashMap
divides the map into segments (or buckets), enabling fine-grained locking. Updates to one segment don’t block operations on others, ensuring consistent iteration.Fail-Safe Iterators: Its iterators are designed to work concurrently with modifications, ensuring safe traversal even during updates.
Efficiency
ConcurrentHashMap
avoids synchronizing the entire map, making it faster for concurrent reads and writes compared to other thread-safe alternatives likeCollections.synchronizedMap()
.
K, But When Does HashMap Fail Then?
HashMap
iterators are fail-fast. If the map is structurally modified (but not via the iterator) during iteration (via put
, remove
, etc.), the iterator detects the modification and throws a ConcurrentModificationException
.
Please check the official documentation for further reading on ConcurrentModificationException 📌
❗️This mechanism is designed to prevent unpredictable behavior when the map’s structure changes (again - not via the iterator itself) mid-iteration. Which is tackling a different problem i.e. it can be leveraged to solve different types of problems!
Example of Failure:
HashMap<Character, Integer> map = new HashMap<>();
map.put('a', 1);
map.put('b', 2);
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
map.put('c', 3); // Structural modification during iteration
}
Result:
java.util.ConcurrentModificationException
Real-World Example: Why ConcurrentHashMap is Necessary
To get a better sense of it, let’s go through an example of how this might help in designing some sort of a rate limiter 👀
Imagine a scenario where you’re building a high-concurrency web server that tracks API request counts per endpoint:
HashMap: Using a
HashMap
to store endpoint counts might work fine in a single-threaded environment. However, in a real-world scenario with multiple threads updating the counts concurrently, you’ll likely encounter aConcurrentModificationException
.ConcurrentHashMap: Replacing
HashMap
withConcurrentHashMap
ensures that multiple threads can safely update the counts without causing exceptions. For instance:
ConcurrentHashMap<String, Integer> requestCounts = new ConcurrentHashMap<>();
requestCounts.put("/api/users", 0);
// Increment request counts safely
requestCounts.compute("/api/users", (key, val) -> val + 1);
Here, the ConcurrentHashMap
allows simultaneous reads and writes, ensuring thread safety and consistent results without additional synchronization.
Choosing Between HashMap and ConcurrentHashMap
Use HashMap
When:
Single-Threaded Applications:
Example: Caching intermediate results in a batch data processing pipeline.
Read-Only or Build-Once Maps:
Example: Mapping configuration keys to values in a settings module.
Use ConcurrentHashMap
When:
Concurrent Modifications:
Example: Counting API request hits per endpoint in a high-concurrency web server.
Frequent Reads and Writes:
Example: Real-time tracking of user sessions in a distributed application.
What Have We Learned?
We need a better understanding of our tools:
Choose the right map for your use case.
HashMap
is great for simplicity and performance in single-threaded scenarios, whileConcurrentHashMap
excels in concurrent environments.
Don’t Neglect Exception:
Don’t ignore
ConcurrentModificationException
as a trivial issue. Instead, address it by understanding its cause and choosing the appropriate data structure.
Think Scalably:
Real-world systems often demand resilient solutions. Adopting thread-safe collections like
ConcurrentHashMap
ensures your application is robust and scalable.
🔑 Takeaways
📌 Maps are cool and VERY important every engineer should know!
🌎 There are actually more real-world usages of maps than you can think of
🔨
ConcurrentHashMap
is a powerful tool for handling concurrent modifications safely.⚖️ Use
HashMap
for single-threaded or read-only contexts, andConcurrentHashMap
for concurrent scenarios.🤕 Understanding these differences can save you from debugging headaches and improve the resilience of your applications.
Can you see how each emoji is mapped to the takeaway? 😉
Have you faced similar challenges? Share your experiences in the comments—let’s learn from each other! 🚀
If you want to support me & 2X your salary at the same time, join me and many more like-minded folks at TopCoding 🔥
👉 Just click the button & you will get a FREE consultation / reality-check on your skills!
There are tons of testimonials you can look at before enrolling here! 🚀