📌 Singleton Design Pattern in Java The Singleton pattern ensures that a class has only one instance and provides a global access point to it. 1️⃣ Why Singleton? Used when: • Only one object is required • Shared resource management • Configuration handling • Logging frameworks • Database connection pools 2️⃣ Basic Singleton (Not Thread-Safe) class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } Problem: • Not thread-safe • Multiple threads may create multiple instances 3️⃣ Thread-Safe (Synchronized Method) public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } Issue: • Slower due to synchronization on every call 4️⃣ Double-Checked Locking (Efficient) private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } Why volatile? • Prevents instruction reordering • Ensures visibility across threads 5️⃣ Best Approach (Recommended) Using Enum: enum Singleton { INSTANCE; } Benefits: ✔ Thread-safe ✔ Prevents reflection attacks ✔ Serialization safe ✔ Simple and clean 🧠 Key Takeaway Singleton seems simple, but thread safety makes it complex. Understanding its implementations shows strong concurrency knowledge. #Java #DesignPatterns #Singleton #BackendDevelopment
Java Singleton Pattern: Thread-Safe Implementations and Best Practices
More Relevant Posts
-
What if you want to write a program that allows only one object of a class? The first concept that comes to mind is the Singleton Class. I was exploring different ways to implement Singleton in Java while studying Low Level Design. I am also attaching the GitHub link where I implemented these approaches: https://lnkd.in/gkmjad72 There are multiple ways to achieve Singleton in Java. 1. Basic Singleton In this approach, we create a class named Singleton. • We declare a private static variable INSTANCE to hold the object. • The constructor is private so that no one can create an object using the new keyword. • We provide a public static method getInstance() which creates the object only if INSTANCE is null. Otherwise it simply returns the existing instance. So problem solved? 😁 Not really. Will this work correctly in a multithreaded environment? If two threads call getInstance() at the same time when INSTANCE is null, both threads might create two different objects. Now it is no longer a Singleton. But don't worry, there are solutions. 2. Method Synchronized Locking We can use the synchronized keyword with the getInstance() method. This ensures mutual exclusion, meaning only one thread can enter the method at a time. But there is still a drawback. Even if the instance is already created, every thread calling getInstance() still needs to acquire the lock, which can affect performance. So instead of synchronizing the whole method, we can use block level synchronization. 3. Block Synchronized Locking Here we synchronize only the block where we check if INSTANCE is null. This reduces unnecessary locking and improves performance. Since synchronized requires locks and additional memory, Java also provides a popular and cleaner approach. 4. Bill Pugh Singleton This approach uses a static inner helper class to create the instance. It provides: • Lazy initialization • Thread safety • Better performance Where and when you used these approaches, write down them in comments. #Java #DesignPatterns #LLD #SoftwareEngineering
To view or add a comment, sign in
-
-
Enum based state machines strike a pragmatic balance between purity and practicality, they remove architectural ceremony while preserving clear transition semantics, in other words, the design manages to be both object oriented and refreshingly straightforward which is rather refreshing in enterprise #Java, normally achieving simplicity requires three frameworks, a dependency injection container, and a philosophical debate about annotations, here you simply use an enum and get on with your life.....quite revolutionary, really.... A state machine models systems whose behaviour changes depending on their current state, a workflow engine, a payment lifecycle, or even something as mundane as a login process can move between states with explicit transitions, traditionally in Java this is implemented with the classic Gang of Four State pattern.m, you define an interface representing a state, create concrete classes for each state, and delegate behaviour through polymorphism, elegant in theory, but in practice it often explodes into a small zoo of classes that exist purely to say “I am the Pending state” or “I am the Approved state”, splendid architecture, slightly exhausting to maintain. The enum based approach compresses that structure into a single construct, each enum constant represents a state, and each constant overrides behaviour that defines what happens in that state because enums in Java can contain methods and even abstract methods, each state can implement its own transition logic, a typical design defines an abstract method such as next() or handle(), and each enum constant overrides it to return the next state or perform state specific actions. The result is surprisingly clean, all states and transitions are visible in one place, which improves readability and reduces boilerplate, there is no need for dozens of tiny classes, and persistence becomes trivial because an enum can be stored as a simple value in a database or ORM mapping, the pattern also aligns well with command query separation because the transition method returns the next state rather than mutating global logic. The elegance comes from exploiting polymorphism inside the enum, ech constant behaves like its own specialised class, the calling code simply delegates behaviour to the current state, and the state decides what to do next, in small to medium workflows this can be remarkably expressive. Of course the technique has limits, and here reality rudely intrudes, when business logic grows complex, stuffing everything into an enum begins to resemble cramming an elephant into a teacup, adding many transitions or conditions can make the enum bloated and harder to extend, it can also violate the open closed principle because adding new states requires modifying the existing enum definition https://lnkd.in/eeQybRuW
To view or add a comment, sign in
-
Java records are powerful. But they are not a replacement for every POJO. That is where many teams get the migration decision wrong. A record is best when your type is mainly a transparent carrier for a fixed set of values. Java gives you the constructor, accessors, equals(), hashCode(), and toString() automatically, which makes records great for DTOs, request/response models, and small value objects. But records also come with important limits. A record is shallowly immutable, its components are fixed in the header, it cannot extend another class because it already extends java.lang.Record, and you cannot add extra instance fields outside the declared components. You can still add validation in a canonical or compact constructor, but records are a poor fit when the model needs mutable state, framework-style setters, or inheritance-heavy design. So the real question is not: “Should we convert all POJOs to records?” The better question is: “Which POJOs are actually just data carriers?” That is where records shine. A practical rule: use records for immutable data transfer shapes, keep normal classes for JPA entities, mutable domain objects, lifecycle-heavy models, and cases where behavior and state evolve over time. Also, one important clarification: this is not really a “Java 25 only” story. Records became a permanent Java feature in Java 16, and Java 25 documents them as part of the standard language model. So no, the answer is not “change every POJO to record.” Change only the POJOs that truly represent fixed data. Where do you draw the line in your codebase: DTOs only, or value objects too? #Java #Java25 #JavaRecords #SoftwareEngineering #BackendDevelopment #CleanCode #JavaDeveloper #Programming #SystemDesign #TechLeadership
To view or add a comment, sign in
-
-
✨🪄 Day 42 of 90 – Java Backend Development 🔥☄️ The Java Virtual Machine (JVM) is the invisible engine that allows Java applications to run on any device or operating system without modification. Acting as a crucial abstraction layer between compiled Java code and the underlying hardware, it fulfills the famous "Write Once, Run Anywhere" (WORA) promise. When you compile a Java program, it isn't turned into machine-specific code; instead, it becomes bytecode, which the JVM then interprets or compiles on-the-fly into instructions the local processor understands. Beyond just execution, the JVM is a sophisticated environment that manages memory automatically through Garbage Collection, optimizes performance via Just-In-Time (JIT) compilation, and enforces strict security boundaries, making it one of the most robust and widely used runtime environments in modern computing. 👉 Key responsibilities of the JVM i)Loading Code: Uses Class Loaders to pull in the necessary files. ii)Verifying Code: Ensures the bytecode doesn't violate security or structural constraints. iii)Executing Code: Converts bytecode into native machine code. iv)Memory Management: Allocates space for objects and automatically cleans up unused memory. 👉 How Java program runs? i)You write code → Hello.java ii)Compiler converts it → Hello.class (bytecode) iii)JVM loads the class iv)JVM verifies the bytecode v)Execution Engine runs it vi)Output is produced. 👉 Main components of JVM 👉 Class Loader Subsystem i)Loads .class files into memory ii)Performs: Loading Linking Initialization 👉 Runtime data areas (Memory Areas) JVM divides memory into: Heap → Stores objects Stack → Stores method calls & local variables Method Area → Stores class metadata, static variables PC Register → Keeps track of current instruction Native Method Stack → For native methods (like C/C++) 👉 Execution engine Executes bytecode Contains: Interpreter → Line-by-line execution JIT (Just-In-Time) Compiler → Converts bytecode into native machine code for faster performance 👉 Garbage Collector (GC) Automatically deletes unused objects from Heap Prevents memory leaks No manual memory management (unlike C/C++) #JVM #Compiler #Interepter #JavaEnvironment
To view or add a comment, sign in
-
-
Saga Pattern and Two-Phase Commit in Java Saga and Two-Phase Commit (2PC) are approaches to managing distributed transactions in microservices, where operations span multiple databases or services, as in Java and Spring. They address data consistency issues when single-database ACID transactions fall short. Saga suits high availability, while 2PC ensures strict atomicity. How the Saga Pattern Works✅ Saga breaks a long transaction into local steps, each with a compensating action for rollback. • Orchestration: A central coordinator manages steps (e.g., order → payment → warehouse). On failure, compensations run in reverse. • Choreography: Services communicate via events (Kafka or RabbitMQ), without a coordinator—each step triggers the next. In Java, implement via Spring Boot with Axon Framework or Eventuate Tram: use @SagaStart and @SagaEnd annotations for steps. Example: reduce warehouse stock + deduct payment; if payment fails, compensate by returning goods. How Two-Phase Commit (2PC) Works✅ 2PC is a blocking protocol with a coordinator and two phases: prepare and commit. • Phase 1 (Prepare): Coordinator asks participants (DBs, services) if ready; they reserve resources and vote YES/NO. • Phase 2 (Commit/Rollback): All YES → commit; else rollback. Locks resources until done. In Java/Spring, use JTA (Java Transaction API) with Atomikos or Narayana: @Transactional with propagation=REQUIRED and xa-data-source for multiple DBs. Example: two DBs (warehouse and bank) sync via UserTransaction
To view or add a comment, sign in
-
Understanding Design Patterns in Java – A Must for Every Backend Developer Writing code is easy. Writing scalable & maintainable code . That’s where Design Patterns come in. Design Patterns are reusable solutions to common software design problems. They help us write clean, flexible code. Here are 5 must-know Design Patterns every Java developer should understand: 🔹 Singleton Pattern Ensures only one instance of a class exists. Used in: Logging, Configuration classes, Database connections. 🔹 Factory Pattern Creates objects without exposing the creation logic. Used when object creation is complex or depends on conditions. 🔹 Builder Pattern Helps construct complex objects step-by-step. Very useful when a class has many optional parameters. 🔹 Observer Pattern Defines a one-to-many dependency between objects. Common in event-driven systems and messaging. 🔹 Strategy Pattern Allows selecting an algorithm’s behavior at runtime. Great for replacing large if-else or switch cases. -> In Spring Boot, many internal components use these patterns (like Bean creation, Event Listeners, etc.). Learning design patterns changed the way I think about system design. . #Java #BackendDevelopment #SpringBoot #DesignPatterns #InterviewPreparation #Backendjavadeveloper
To view or add a comment, sign in
-
🚀 Java Series (2) – Understanding Java Variables (With JVM Memory Mapping) In Java, a variable is a name given to a memory location. It acts like a container that stores data during program execution. 👉 Variable = “vary + able” Meaning: Its value can change. Every variable must have a data type, which defines what kind of data it can store. 🎯 Types of Java Variables 1️⃣ Local Variables 2️⃣ Instance Variables 3️⃣ Static Variables Let’s understand them clearly — and where they are stored inside the JVM. 1️⃣ Local Variable 📌 Declared inside: Method Constructor Block 🔹 Characteristics • Created when method is called • Destroyed when method ends • Must be initialized before use • Scope limited to method/block 📍 Stored In JVM: 👉 Stack Memory When a method is invoked: A new stack frame is created Local variables are stored inside that frame When method completes → frame is removed 2️⃣ Instance Variable 📌 Declared inside class but outside methods. 🔹 Characteristics • Belongs to object • Each object has its own copy • Gets default values • Created when object is created 📍 Stored In JVM: 👉 Heap Memory Object stored in Heap Instance variables stored inside that object Reference variable (s) stored in Stack 3️⃣ Static Variable 📌 Declared using static keyword. 🔹 Characteristics • Belongs to class (not object) • Only one copy exists • Shared among all objects • Loaded once when class is loaded 📍 Stored In JVM: 👉 Method Area (Class Area) Static variables are stored in: Method Area Along with class metadata They are created when class is loaded by ClassLoader.
To view or add a comment, sign in
-
-
Can you update a private final variable in Java using Reflection? Most developers will say NO… But the real answer is a bit more interesting 👇 ⸻ In Java: • private → restricts access within the class • final → prevents reassignment after initialization So ideally, a private final variable should remain unchanged ❌ ⸻ 🔍 But Reflection changes the game… It allows you to bypass access control and even modify a final field: class Person { private final int age = 21; } Field field = Person.class.getDeclaredField("age"); field.setAccessible(true); Person p = new Person(); field.set(p, 30); System.out.println(field.get(p)); // 30 😮 ⚠️ Before you get excited… read this: • JVM may inline final values → results can be unpredictable • Behavior can differ across Java versions • Breaks immutability and encapsulation • Can introduce hard-to-debug issues ⸻ 🚫 Why you should avoid this in real projects: ❌ Violates clean code principles ❌ Unsafe and not future-proof ❌ Makes your codebase harder to maintain ⸻ 🚀 Better approach: If a value needs to change: 👉 Don’t mark it final 👉 Or redesign your class for proper mutability
To view or add a comment, sign in
-
🚀 The Invisible Wall in Java Memory - Why Your Code Crashes Even With 32GB RAM Ever encountered this? Exception in thread "main" java.lang.StackOverflowError The server has 32GB RAM. The heap is barely touched. And yet - crash. What’s actually happening Java memory isn’t one big pool. Every thread gets its own stack - typically ~1MB by default. That stack holds: • Method frames • Local primitives • Object references It’s fast. It’s limited. And it’s completely separate from the heap. Deep recursion burns through that 1MB quickly. It doesn’t matter how much heap you have. 𝗦𝘁𝗮𝗰𝗸𝗢𝘃𝗲𝗿𝗳𝗹𝗼𝘄𝗘𝗿𝗿𝗼𝗿 ≠ 𝗢𝘂𝘁𝗢𝗳𝗠𝗲𝗺𝗼𝗿𝘆𝗘𝗿𝗿𝗼𝗿 One means your thread stack is exhausted The other means your heap is exhausted Confusing them costs hours in production debugging. JVM Heap tip • Always set -𝗫𝗺𝘀 and -𝗫𝗺𝘅 explicitly in production • Never rely on JVM defaults - it guesses, and guessing is expensive Common misconception When StackOverflowError hits, the first instinct is: 👉 “Increase the RAM.” Wrong lever entirely. • Stack isn’t heap • You can’t throw hardware at it • Recursion works… until it doesn’t • In production, “until it doesn’t” comes faster than expected The right mental model ✔️ Prefer iteration for deep recursion ✔️ -𝗫𝘀𝘀 controls thread stack size, but tune it only as a last resort ✔️ Set -𝗫𝗺𝘀 and -𝗫𝗺𝘅 explicitly - don’t trust JVM defaults ✔️ Remember: every thread has its own stack ✔️ Treat StackOverflowError as a design signal, not a runtime surprise Memory management isn’t just a C++ concern- every Java engineer should own it too.
To view or add a comment, sign in
-
-
🖥️ Slide 1 – Title Java Servlet URL Mapping 💡 Understanding how a server decides which servlet should handle a client request 📚 Learning Advanced Java – Servlets Topics covered: URL Pattern Mapping Request Handling WebLogic Deployment Servlet Architecture 👨💻 Exploring Backend Development with Java 🔗 Slide 2 – 7 Types of URL Mapping 1️⃣ Exact Match /demo1 2️⃣ Default Page /index.html 3️⃣ HTML Mapping /abc.html 4️⃣ Default Servlet / 5️⃣ Extension Match *.go 6️⃣ Path Match /* 7️⃣ Folder Match /test/* 💡 These patterns help the Servlet Container route requests correctly. ⚙️ Slide 3 – Servlet Architecture Client → Web Server → Servlet Container → Servlet → Response Steps: 1️⃣ Client sends HTTP Request 2️⃣ Web server forwards request to Servlet Container 3️⃣ Container finds the matching servlet using URL mapping 4️⃣ Servlet processes the request 5️⃣ Server sends HTTP Response back to the client
To view or add a comment, sign in
-
Explore related topics
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