Singleton breaks easily if you ignore concurrency A Singleton may look correct in single-threaded code. Under multiple threads, it can silently break. What actually goes wrong: 🔹 Two threads enter creation logic at the same time 🔹 Multiple instances get created 🔹 Bugs appear only under load, not locally 🔹 The code “looks fine” but isn’t safe Why this happens: 🔹 Object creation is not automatically thread-safe 🔹 Without proper memory visibility, one thread may see a half-constructed object 🔹 These issues are timing-dependent and hard to reproduce. The real learning: Singleton is not about making the constructor private. It’s about safe publication and controlled initialization. If concurrency is part of your system — the design must assume multiple threads from day one. Core Java depth shows up here: simple patterns, complex consequences. #CoreJava #Java #Concurrency #Multithreading #BackendEngineering #SoftwareEngineering
Manoj Seth’s Post
More Relevant Posts
-
𝗧𝗵𝗲 𝗝𝗮𝘃𝗮 𝗠𝗲𝗺𝗼𝗿𝘆 𝗠𝗼𝗱𝗲𝗹 𝗜𝘀 𝗪𝗵𝘆 𝗬𝗼𝘂𝗿 𝗖𝗼𝗱𝗲 “𝗦𝗼𝗺𝗲𝘁𝗶𝗺𝗲𝘀” 𝗕𝗿𝗲𝗮𝗸𝘀 If your multithreaded Java code: • works locally • fails randomly in prod • behaves differently under load The issue is often not logic. It’s the Java Memory Model (JMM). Here’s the uncomfortable truth 👇 In Java, visibility is not guaranteed unless you make it explicit. • One thread can update a variable • Another thread may still see the old value • Even if the code “looks correct” Why? Because CPU caches, reordering, and compiler optimizations are allowed by the JMM. That’s why: • volatile exists • synchronized exists • final has special guarantees • Atomic* classes matter They don’t just protect data — they create happens-before relationships. Without happens-before, your code has undefined behavior at runtime. Multithreading bugs are dangerous because: ❌ they don’t fail fast ❌ they don’t fail consistently ❌ logs don’t help much Concurrency works only when you respect the memory model — not just the syntax. #Java #JavaConcurrency #JavaMemoryModel #AdvancedJava #BackendEngineering #SystemDesign
To view or add a comment, sign in
-
A lot of performance issues in Java applications are caused by design choices made long before the system goes to production. The JVM is incredibly powerful, but it rewards developers who understand how it actually behaves at runtime. One common example is object allocation. Modern garbage collectors are highly optimized, yet excessive short lived object creation in hot paths still increases GC pressure and latency. Simple changes such as reusing objects where appropriate, avoiding unnecessary boxing, and being mindful with Streams inside tight loops can produce measurable improvements. Concurrency is another area where small decisions have big consequences. Using the right executor strategy, limiting shared mutable state, and understanding how synchronization impacts throughput can dramatically improve scalability. High level tools like Completable Future and structured concurrency simplify async workflows, but they still require careful thinking about thread usage and blocking calls. JVM observability is equally important. Tools such as JFR, VisualVM, and GC logs provide deep insight into memory behavior, thread contention, and CPU hotspots. Reading these signals early helps prevent slow degradation under real traffic. Java remains a strong choice for large scale systems because of its maturity and ecosystem. Teams that combine solid language fundamentals with JVM level awareness consistently build services that stay fast and stable as they grow. #Java #JVM #JavaPerformance #BackendEngineering #ScalableSystems #Concurrency #GarbageCollection #SpringBoot #SoftwareArchitecture #DevTips
To view or add a comment, sign in
-
-
⚠️ Defaults Are the Most Dangerous Thing in Java Most production issues don’t come from bad code. They come from defaults used without thinking at scale. Defaults work… until traffic, latency, and failures show up. 🔍 Problem 1: Thread pool defaults Executors.newFixedThreadPool(100) On an 8-core machine: threads fight for CPU context switching increases latency grows under load ✅ Better approach Size pools based on workload CPU-bound → ~ number of cores IO-bound → measure wait time Always use bounded queues 🔍 Problem 2: No timeouts restTemplate.getForObject(url, Response.class); If downstream slows: threads block pools exhaust requests pile up ✅ Better approach Always configure: connection timeout read timeout Fail fast > fail silently 🔍 Problem 3: Connection pool defaults Defaults often allow: unlimited waiting or poor burst handling Result: slow degradation cascading failures ✅ Better approach Cap max connections Set wait timeouts Monitor pool saturation 🧠 The real lesson Defaults are: guesses made by frameworks not guarantees for your system Production stability comes from explicit limits, not assumptions. #BackendEngineering #Java #SoftwareEngineering #Multithreading #Concurrency #SystemDesign #SpringBoot
To view or add a comment, sign in
-
Stop treating the JVM like a black box. 🛑 If you want to write high-performance Java, you have to understand what’s happening with memory. It goes way beyond just knowing the difference between "Stack and Heap". Real optimization comes from mastering the details: 🔹 References: Knowing when to reach for Strong, Weak, or Soft references. 🔹 Heap Structure: How objects actually travel through the Young Generation (Eden & Survivor spaces) into the Old Generation or Metaspace. 🔹 Garbage Collection: Picking the right strategy—whether that’s Parallel, G1, or low-latency options like ZGC Which Garbage Collector are you running in production these days? Let me know below! 👇 #Java #JVM #MemoryManagement #SoftwareEngineering #BackendDevelopment #JavaPerformance
To view or add a comment, sign in
-
-
🚨 Parallel Streams are not always your friend 🚨 Parallel streams in Java look tempting. More cores. More threads. Faster execution… right? Not always. Recently, I ran into a production issue that reminded me why parallelStream() needs extra care. ⚠️ ArrayList + parallelStream() = risky ArrayList is not thread-safe. When multiple threads add elements at the same time, things can break. What I observed: ❌ Missing elements ❌ Inconsistent list size ❌ Occasional ArrayIndexOutOfBoundsException 🧠 What actually goes wrong (see diagram) Multiple threads read the same internal size All try to write at the same index One thread resizes the array while others keep writing 💥 Race condition → corrupted state → exception ✅ Better approaches Avoid shared mutable state: List<Result> results = items.parallelStream().map(this::process).toList(); Or simply: items.stream().map(this::process).toList(); 💡 Takeaway Parallel streams are powerful, but: ❌ Unsafe with ArrayList mutation ❌ Easy to misuse, hard to debug ❌ Not always faster Parallelism is a tool, not a default choice. Sometimes, boring and sequential wins. #Java #ParallelStreams #Concurrency #ArrayList #RaceCondition #Performance #LessonsLearned
To view or add a comment, sign in
-
-
🚀 𝐉𝐚𝐯𝐚 𝐓𝐞𝐜𝐡 𝐃𝐫𝐨𝐩: 𝐟𝐢𝐧𝐚𝐥 𝐯𝐬 𝐬𝐞𝐚𝐥𝐞𝐝 𝐜𝐥𝐚𝐬𝐬𝐞𝐬 In Java, we’ve used final classes for years to lock down behavior. They’re great when extension would break invariants or introduce bugs. But sealed classes change the game. 𝐟𝐢𝐧𝐚𝐥 answers: 👉 “This class must NOT be extended.” 𝐬𝐞𝐚𝐥𝐞𝐝 answers: 👉 “This class CAN be extended — but only in ways I explicitly allow.” Why this matters in real systems: - You get controlled polymorphism - The compiler knows all valid subtypes - Exhaustive switch becomes safer and cleaner - Your domain model becomes explicit, not implicit 𝐟𝐢𝐧𝐚𝐥 is about restriction. 𝐬𝐞𝐚𝐥𝐞𝐝 is about designing boundaries. If you’re modeling domains, workflows, or state machines, 𝐬𝐞𝐚𝐥𝐞𝐝 classes often express intent better than 𝐟𝐢𝐧𝐚𝐥 ever could. With 𝐬𝐞𝐚𝐥𝐞𝐝, the compiler knows all possible implementations. That means safer refactors, exhaustive switch, and clearer domain boundaries. ☕ Modern Java isn’t about more features — it’s about better constraints. #Java #SoftwareEngineering #CleanCode #DomainModel #Backend #Spring #Kotlin #JVM
To view or add a comment, sign in
-
-
High-throughput Java services still tuned by thread-pool math? That’s costing you latency and engineering cycles. Java 21’s virtual threads let you simplify concurrency for I/O-bound services while keeping predictable latency — if you handle a few important trade-offs correctly. Problem Most backend teams over-provision fixed thread pools to hide blocking I/O, increasing context switching and unpredictable GC pressure. Sizing becomes guesswork. What to do instead
To view or add a comment, sign in
-
How Virtual Threads Can Improve Java Backend Performance 🧵⚡ Traditional Java threads are powerful — but expensive. Each platform thread maps to an OS thread. That means memory overhead, context switching, and limits under high concurrency. Enter Virtual Threads (Project Loom). Instead of tying every request to a heavyweight OS thread, virtual threads are: ✅ Lightweight ✅ Managed by the JVM ✅ Created in thousands (even millions) Why This Matters In typical backend systems: - Most time is spent waiting (DB calls, APIs, network I/O) - Threads sit idle, blocking resources With virtual threads: 👉 Blocking code becomes cheap 👉 You can keep a simple synchronous programming model 👉 Throughput improves without complex async frameworks The Real Win You don’t need to rewrite everything into reactive style. You can write clean, readable, imperative code — and still handle massive concurrency efficiently. Virtual threads aren’t magic. But for IO-heavy microservices, they can be a game changer. #Java #VirtualThreads #ProjectLoom #BackendEngineering #Performance #Scalability
To view or add a comment, sign in
-
Most Java backend systems don’t break because of performance. They break because of tight coupling. When controllers depend on concrete services, and services depend on concrete implementations, change becomes risky. That’s exactly why interfaces exist. An interface is not boilerplate. It’s a boundary. High-level code should depend on behavior, not details. Low-level code should implement those behaviors. This flips the dependency direction. That’s dependency inversion. I explained this in my latest article with real Java examples see it here: 👉 https://lnkd.in/dAwihfPm Good design isn’t about adding patterns everywhere. It’s about protecting your core logic from change. #Java #BackendDevelopment #SystemDesign #OOP #CleanCode #SoftwareArchitecture
To view or add a comment, sign in
-
Java☕ — Garbage Collection♻️ Earlier, I thought GC was magic. Objects disappear… somehow. Then I learned the basics of how JVM actually cleans memory. Key idea that clicked for me 👇 GC removes objects that are no longer reachable. 📝JVM divides heap into: ✅Young Generation (Eden, Survivor) ✅Old Generation New objects → Young Gen Long-living objects → Old Gen #Java_Code User u = new User(); u = null; // eligible for GC 📝Important realization: You don’t control GC — you design code to help it. 📝Good GC behavior comes from: ✅Fewer unnecessary objects ✅Short object lifetimes ✅Clearing references when done Java isn’t leaking memory. Bad references are. #Java #GarbageCollection #JVM #MemoryManagement
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