🔥 Day 4 — Race Conditions in Java: The Silent Bug That Breaks Production “It works perfectly in my local tests.” 👉 Famous last words before a production issue. One of the most dangerous bugs in concurrent systems is a race condition. ⚠ What is a Race Condition? When multiple threads access and modify shared data at the same time, leading to unpredictable results. 💻 Simple Example int count = 0; public void increment() { count++; // ❌ Not thread-safe } Run this with multiple threads → Expected: 1000 Actual: random number (like 732, 845...) ❌ Why this happens? count++ is NOT atomic. It involves: - Read - Increment - Write Multiple threads interfere between these steps. ✅ Fix Options ✔ Use synchronized synchronized(this) { count++; } ✔ Use AtomicInteger AtomicInteger count = new AtomicInteger(0); count.incrementAndGet(); 💡 Architect Insight: Race conditions are silent bugs — they: ❌ Don’t fail in testing ❌ Appear only under load ❌ Are extremely hard to debug In real systems, they can cause: - Duplicate payments 💸 - Incorrect balances - Data corruption 🚀 Rule of Thumb: If data is shared across threads → 👉 Always think about thread safety first 👉 Have you ever faced a race condition in production? What happened? #100DaysOfJavaArchitecture #Java #Concurrency #SoftwareArchitecture #Microservices
Java Race Conditions: Silent Bugs in Concurrent Systems
More Relevant Posts
-
Most Java performance issues don’t show up in code reviews They show up in object lifetimes. Two pieces of code can look identical: same logic same complexity same output But behave completely differently in production. Why? Because of how long objects live. Example patterns: creating objects inside tight loops → short-lived → frequent GC holding references longer than needed → objects move to old gen caching “just in case” → memory pressure builds silently Nothing looks wrong in the code. But at runtime: GC frequency increases pause times grow latency becomes unpredictable And the worst part? 👉 It doesn’t fail immediately. 👉 It degrades slowly. This is why some systems: pass load tests work fine initially then become unstable weeks later Takeaway: In Java, performance isn’t just about what you do. It’s about how long your data stays alive while doing it. #Java #JVM #Performance #Backend #SoftwareEngineering
To view or add a comment, sign in
-
Most Java developers have used ThreadLocal to pass context — user IDs, request IDs, tenant info — across method calls. It works fine with a few hundred threads. But with virtual threads in Java 21, "fine" becomes a memory problem fast. With 1 million virtual threads, you get 1 million ThreadLocalMap instances — each holding mutable, heap-allocated state that GC has to clean up. And because ThreadLocal is mutable and global, silent overwrites like this are a real risk in large systems: userContext.set(userA); // ... deep somewhere ... userContext.set(userB); // overrides without warning Java 21 introduces ScopedValue — the right tool for virtual threads: ScopedValue.where(USER, userA).run(() -> { // USER is safely available here, immutably }); It's immutable, scoped to an execution block, requires no per-thread storage, and cleans itself up automatically. No more silent overrides. No memory bloat. No manual remove() calls. In short: ThreadLocal was designed for few, long-lived threads. ScopedValue is designed for millions of short-lived virtual threads. If you're building high-concurrency APIs with Spring Boot + virtual threads and still using ThreadLocal for request context — this switch can meaningfully reduce your memory footprint and make your code safer. Are you already using ScopedValue in production, or still on ThreadLocal? Would love to hear what's holding teams back. #Java #Java21 #VirtualThreads #ProjectLoom #BackendEngineering #SpringBoot #SoftwareEngineering
To view or add a comment, sign in
-
Forgetting a 𝑻𝒉𝒓𝒆𝒂𝒅𝑳𝒐𝒄𝒂𝒍.𝒓𝒆𝒎𝒐𝒗𝒆() isn’t just messy anymore it can turn request-scoped context into a bug with virtualthreads. Java 25/26 now give us the cleaner model: → 𝑺𝒄𝒐𝒑𝒆𝒅𝑽𝒂𝒍𝒖𝒆 (Final - JEP 506) → 𝑺𝒕𝒓𝒖𝒄𝒕𝒖𝒓𝒆𝒅𝑻𝒂𝒔𝒌𝑺𝒄𝒐𝒑𝒆 (Preview - JEP 505 in Java 25, JEP 525 in Java 26) 𝑻𝒉𝒆 𝒏𝒆𝒘 𝒎𝒐𝒅𝒆𝒍 𝒊𝒔 𝒔𝒊𝒎𝒑𝒍𝒆: 1. Bind context 𝒐𝒏𝒄𝒆 at the request edge 2. Fork parallel work with 𝑺𝒕𝒓𝒖𝒄𝒕𝒖𝒓𝒆𝒅𝑻𝒂𝒔𝒌𝑺𝒄𝒐𝒑𝒆 3. Child tasks 𝒊𝒏𝒉𝒆𝒓𝒊𝒕 the bound context 4. Scope ends → the binding is 𝒈𝒐𝒏𝒆 𝒔𝒕𝒓𝒖𝒄𝒕𝒖𝒓𝒂𝒍𝒍𝒚 No manual cleanup. No per-task rebinding. No 𝑓𝑖𝑛𝑎𝑙𝑙𝑦. 𝐓𝐡𝐞 𝐨𝐧𝐞 𝐚𝐫𝐜𝐡𝐢𝐭𝐞𝐜𝐭𝐮𝐫𝐚𝐥 𝐫𝐮𝐥𝐞 𝐭𝐡𝐚𝐭 𝐦𝐚𝐭𝐭𝐞𝐫𝐬 𝐦𝐨𝐬𝐭: ❌ 𝐃𝐨𝐦𝐚𝐢𝐧 𝐝𝐚𝐭𝐚 → method parameters Examples: orderId, customerId, cart ✅ 𝐑𝐞𝐪𝐮𝐞𝐬𝐭-𝐬𝐜𝐨𝐩𝐞𝐝 𝐜𝐨𝐧𝐭𝐞𝐱𝐭 → ScopedValue Examples: traceId, tenantId, auth, feature flags That single distinction removes a surprising amount of noise from service code. From: 𝑯𝒐𝒘 𝒅𝒐 𝑰 𝒑𝒂𝒔𝒔 𝒕𝒉𝒊𝒔 𝒕𝒉𝒓𝒐𝒖𝒈𝒉 15 𝒍𝒂𝒚𝒆𝒓𝒔? To: 𝑾𝒉𝒂𝒕 𝒊𝒔 𝒕𝒉𝒆 𝒔𝒕𝒓𝒖𝒄𝒕𝒖𝒓𝒂𝒍 𝒔𝒄𝒐𝒑𝒆 𝒐𝒇 𝒕𝒉𝒊𝒔 𝒅𝒂𝒕𝒂? That mindset shift is the real upgrade. Detailed walkthrough with examples: https://lnkd.in/gqfDr5rs #Java #Java25 #Java26 #ProjectLoom #ScopedValue #StructuredConcurrency #VirtualThreads #SpringBoot #BackendEngineering #JVM
To view or add a comment, sign in
-
-
🔥 Day 7 — Atomic Classes (AtomicInteger): Simple Fix for Concurrency Issues I’ve seen this pattern quite often in Java code: int count = 0; public void increment() { count++; } Looks correct… but breaks under concurrency. 👉 Because count++ is NOT atomic It actually does: - Read - Increment - Write With multiple threads, updates get lost. ✅ A simple and efficient fix: AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } No synchronized No explicit locks Still thread-safe ✔ ⚙ What makes Atomic classes powerful? - Use CAS (Compare-And-Swap) internally - Avoid blocking threads - Perform better under high concurrency 💡 Where AtomicInteger works best ✔ Counters (requests, metrics, retries) ✔ Flags / simple shared state ✔ High-throughput systems ⚠ Where it’s NOT enough ❌ Multiple variables need to be updated together ❌ Complex business logic ❌ Transaction-like operations 💡 From experience: In one system, replacing synchronized counters with AtomicInteger reduced thread contention significantly under load. Small change. Big impact. 👉 Do you prefer Atomic classes or synchronized for counters? #100DaysOfJavaArchitecture #Java #Concurrency #SoftwareArchitecture #Microservices
To view or add a comment, sign in
-
-
ConcurrentHashMap vs HashMap: When to Use What One of the most common mistakes I still see in Java systems 👇 Using HashMap in a multi-threaded environment. It may work in development… but can fail badly in production. Let’s break it down 👇 ⚠️ HashMap (Not Thread-Safe) No synchronization Multiple threads can modify it simultaneously Can lead to data corruption or unpredictable behavior 👉 Works fine only in single-threaded scenarios ✅ ConcurrentHashMap (Thread-Safe & Scalable) Designed for concurrent access Uses fine-grained locking (bucket-level) Better performance than synchronized collections 👉 Ideal for high-scale, multi-threaded systems 💻 Example Map<String, Integer> map = new HashMap(); // ❌ Not safe Map<String, Integer> map = new ConcurrentHashMap(); map.compute("count", (k,v) -> v == null ? 1 : v + 1); // ✅ Safe 💡 Architect Insight: In high-scale systems (payments, trading, real-time systems): Using HashMap under concurrency can lead to: ❌ Lost updates ❌ Inconsistent data ❌ Hard-to-debug production issues Always choose the right data structure based on concurrency needs, not just simplicity. 🚀 When to use what? ✔️ Use HashMap → Single-threaded, local processing ✔️ Use ConcurrentHashMap → Multi-threaded, shared data 👉 Have you ever debugged a concurrency issue caused by a HashMap?
To view or add a comment, sign in
-
🚀 𝗝𝗮𝘃𝗮 𝟴 𝗦𝘁𝗿𝗲𝗮𝗺𝘀 – 𝗜𝗻𝘁𝗲𝗿𝗺𝗲𝗱𝗶𝗮𝘁𝗲 𝗖𝗼𝗻𝗰𝗲𝗽𝘁𝘀 𝗘𝘃𝗲𝗿𝘆 𝗗𝗲𝘃𝗲𝗹𝗼𝗽𝗲𝗿 𝗦𝗵𝗼𝘂𝗹𝗱 𝗠𝗮𝘀𝘁𝗲𝗿 Streams revolutionized how we process collections in Java. Once you’re comfortable with the basics, it’s time to explore the intermediate concepts that unlock their full potential: 1️⃣ 𝗟𝗮𝘇𝘆 𝗘𝘃𝗮𝗹𝘂𝗮𝘁𝗶𝗼𝗻 Operations like 𝘧𝘪𝘭𝘵𝘦𝘳() and 𝘮𝘢𝘱() don’t run until a terminal operation (collect(), reduce(), etc.) is invoked. This allows efficient, optimized pipelines. 2️⃣ 𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹 𝗦𝘁𝗿𝗲𝗮𝗺𝘀 Use parallelStream() to leverage multi-core processors for heavy computations. Great for CPU-intensive tasks, but be mindful of thread safety and overhead. 3️⃣ 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗼𝗿𝘀 𝗳𝗼𝗿 𝗔𝗱𝘃𝗮𝗻𝗰𝗲𝗱 𝗚𝗿𝗼𝘂𝗽𝗶𝗻𝗴 The Collectors utility class enables powerful aggregations: groupingBy() → classify data partitioningBy() → split by boolean condition joining() → concatenate strings 4️⃣ 𝗥𝗲𝗱𝘂𝗰𝘁𝗶𝗼𝗻 𝗢𝗽𝗲𝗿𝗮𝘁𝗶𝗼𝗻𝘀 Beyond built-in collectors, reduce() lets you define custom aggregation logic. Example: finding the longest string in a list. 5️⃣ 𝗙𝗹𝗮𝘁𝗠𝗮𝗽 𝗳𝗼𝗿 𝗡𝗲𝘀𝘁𝗲𝗱 𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗲𝘀 Flatten lists of lists into a single stream for easier processing. 6️⃣ 𝗖𝘂𝘀𝘁𝗼𝗺 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗼𝗿𝘀 Build specialized collectors with Collector.of() when default ones don’t fit your use case. ⚠️ 𝗕𝗲𝘀𝘁 𝗣𝗿𝗮𝗰𝘁𝗶𝗰𝗲𝘀 • Avoid side effects inside streams. • Use parallel streams wisely (not for small or I/O-bound tasks). • Prefer immutability when working with streams. 💡 Mastering these intermediate concepts makes your Java code more expressive, efficient, and scalable. 👉 Which stream feature do you find most powerful in your projects? #Java #Streams #FunctionalProgramming #IntermediateConcepts #DevTips #CleanCode
To view or add a comment, sign in
-
-
🚀 Java Backend Story: How I Debugged a Slow API in Production Recently, I faced a situation where one of our APIs started responding very slowly in production. What made it tricky was: • It worked fine in development • No errors in logs • CPU and memory usage looked normal But users were experiencing high latency. 🔹 Step 1: Identify the Bottleneck First, I checked: ✔ Application logs ✔ Database query logs ✔ API response time metrics This helped narrow down the issue to a specific endpoint. 🔹 Step 2: Analyze the Flow After tracing the request flow, I found: • Multiple database calls happening inside a loop • Each request triggering repeated queries Classic case of inefficient data fetching. 🔹 Step 3: Optimize the Issue Instead of fetching data repeatedly: ✔ Rewrote the query using JOINs ✔ Reduced multiple DB calls into a single optimized query 🔹 Step 4: Result ✔ Significant reduction in response time ✔ Lower database load ✔ Better performance under concurrent traffic 🔹 Key Learning Production issues are rarely obvious. Debugging is not just about fixing errors — it's about: • Observing system behavior • Identifying bottlenecks • Understanding how different layers interact Sometimes, a small inefficiency can cause a big performance issue at scale. Because in backend systems, performance problems hide in places you least expect. hashtag #Java hashtag #BackendDevelopment hashtag #Debugging hashtag #Performance hashtag #SoftwareEngineering
To view or add a comment, sign in
-
Day 23/100 — Functional Interfaces 🔧 Master these 4, and you unlock the real power of Java 8+ ⚡ ☕ Predicate → test() → boolean Think: Bouncer → allows or rejects isEven.test(4) // true 🍳 Function<T, R> → apply() → transforms data Think: Chef → ingredient → dish length.apply("Java") // 4 🖨️ Consumer → accept() → no return Think: Printer → takes input, returns nothing 🎰 Supplier → get() → no input Think: Vending machine → gives output getRandom.get() 💡 Why it matters: These are the backbone of Streams, Lambdas, and clean functional-style coding in Java. 🔗 Combine Predicates like logic gates: isEven.and(isPositive) // AND isEven.or(isPositive) // OR isEven.negate() // NOT (→ isOdd) 🎯 Challenge: Filter numbers that are BOTH even AND > 10 👇 Predicate isEven = n -> n % 2 == 0; Predicate greaterThan10 = n -> n > 10; numbers.stream() .filter(isEven.and(greaterThan10)) .forEach(System.out::println); Simple concepts. Massive impact. 🚀 #Java #Java8 #FunctionalProgramming #Predicate #Coding #100DaysOfCode #100DaysOfJava #Developers
To view or add a comment, sign in
-
-
Thread Pools to Virtual Threads. 🧵 OutOfMemoryError it is a nightmare that has always haunted Java developers. We're always been stuck with Platform Threads (heavyweight wrappers around OS threads). Since each one cost about 1MB of memory, handling 10,000 concurrent requests meant you either needed a massive, expensive server or had to write complex reactive code that nobody actually wants to debug. Enter Project Loom (Java 21+). I’ve been diving into Virtual Threads, and the "blocking" game has completely changed. Here’s why this matters for the modern backend: Cheap as Chips: Virtual threads are managed by the JVM, not the OS. They only cost a few hundred bytes. You can literally spawn one million threads on a standard laptop without breaking a sweat. The "Thread-per-Request" Revival: We can go back to writing simple, readable, synchronous code. No more "Callback Hell" or complex Mono/Flux chains just to keep the CPU busy while waiting for a database response. Massive Throughput: In I/O-heavy applications (which most Spring Boot apps are), Virtual Threads allow the CPU to switch to other tasks instantly while one thread waits for a slow API or SQL query. How to use it in Spring Boot 3.2+? It’s literally one line in your application.properties: spring.threads.virtual.enabled=true By flipping this switch, Tomcat/Undertow starts using Virtual Threads to handle web requests. It’s a complete paradigm shift that lets us build more scalable systems with less infrastructure cost. The takeaway for teams: We no longer have to choose between "easy-to-read code" and "high-performance code." With Java 21, we get both. #Java #SpringBoot #BackendDevelopment #ProjectLoom #SoftwareEngineering #Scalability #JVM
To view or add a comment, sign in
-
-
🚀 Java Series — Day 4: Thread Synchronization & Race Condition Multithreading boosts performance ⚡ But without control, it can break your application ❌ Today, I explored one of the most critical concepts in Java — Thread Synchronization. 💡 When multiple threads access shared data at the same time, it leads to a Race Condition, causing unpredictable and incorrect results. 🔍 What I Learned: ✔️ What is Race Condition ✔️ Why Thread Safety is important ✔️ How synchronized ensures only one thread executes at a time ✔️ Importance of critical section in multi-threading 💻 Code Insight: class Counter { int count = 0; public synchronized void increment() { count++; } } 👉 Without synchronization → Data inconsistency 👉 With synchronization → Safe & accurate execution 🌍 Real-World Applications: 💰 Banking systems 👥 Multi-user applications ⚙️ Backend APIs handling concurrent requests 💡 Key Takeaway: Thread Synchronization prevents race conditions and ensures your application runs correctly, safely, and reliably in a multi-threaded environment. 📌 Next: Executor Service & Thread Pool — writing scalable and optimized code 🔥 #Java #Multithreading #ThreadSafety #BackendDevelopment #JavaDeveloper #100DaysOfCode #CodingJourney
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development