Intervals Pattern in Java — A Detailed Guide
Intervals problems are mostly about ordering and overlap rules. Once sorted, many become simple linear scans.
Intervals problems are mostly about ordering and overlap rules. Once sorted, many become simple linear scans.
Use heaps when you need repeated access to the smallest or largest element under updates. Java provides this via PriorityQueue.
Monotonic deque extends monotonic-stack thinking to moving windows. It gives fast max/min queries while the window slides.
Java 26 is the next non-LTS release in the six-month cadence. The OpenJDK JDK 26 schedule lists general availability on March 17, 2026, and the JDK 26 projec...
Monotonic stack helps find next/previous greater or smaller elements in linear time. It avoids repeated backward or forward scans.
Binary search is not just for finding a value in a sorted array. It is a decision pattern over monotonic spaces.
Hash-based patterns are the default when you need fast membership checks, counts, or complement lookups. This pattern often converts nested-loop logic into l...
Prefix Sum is one of the highest-leverage DSA patterns. It converts repeated range computations from repeated work into constant-time lookups after linear pr...
Sliding Window is a focused form of the Two Pointers technique. If Two Pointers teaches movement strategy, Sliding Window teaches stateful range management.
Java 25 is an LTS release (GA on September 16, 2025). This article covers all JDK 25 release features, and the major developer-facing items now have fuller e...
Java 21 is an LTS release with major improvements in concurrency, pattern matching, and collections. This article covers all JDK 21 release JEPs. For the fea...
Java 17 is an LTS release. This article covers the most important JDK 17 changes, and for the features most teams adopt directly, the examples are fuller rea...
Java 11 is an LTS release and remains a very common production baseline. This guide covers the most important Java 11 additions, and for the features teams u...
parallelStream() is not a universal performance switch.
Date-time bugs are common in distributed systems:
Async code without clear failure policy becomes fragile quickly. This post focuses on robust CompletableFuture error handling and thread-pool design for prod...
CompletableFuture enables non-blocking service orchestration in Java 8. It is especially useful when an endpoint needs data from multiple downstream services.
Functional interfaces are not just lambda targets. In backend systems they help build reusable policies for validation, mapping, retries, and cross-cutting o...
Optional<T> makes absence explicit in API contracts. Used correctly, it reduces null-related defects and clarifies service-layer behavior. Used incorre...
Collectors are the aggregation engine of the Stream API. In backend code, they are used for:
Two Pointers is one of the most effective techniques for turning brute-force array/string solutions into linear-time solutions.
In most backend systems, a big part of business logic is data transformation:
Java 8 introduced lambda expressions, fundamentally changing how we write backend code.
The hardest part of design patterns is not implementation. It is choosing the right pattern and stopping before abstraction becomes ceremony.
Chain of Responsibility is attractive whenever one big validator starts turning into a wall of conditionals. The promise is simple: separate each rule, keep ...
State becomes useful when an object’s behavior changes meaningfully based on its current lifecycle stage. Without it, classes often fill up with conditionals...
Template Method is a good fit when the overall algorithm is stable, but one or more steps vary by subtype. It is especially common in parsing and import work...
Command turns an action into an object. That sounds simple, but it enables powerful capabilities:
Strategy is one of the most useful patterns in Java because many business rules are really just interchangeable algorithms selected at runtime.
Observer is about decoupling publishers from subscribers. It works well when one state change must trigger multiple downstream reactions that should not be h...
Teams often discover Proxy accidentally. They add authorization, then caching, then maybe rate limiting, and suddenly one object is standing between callers ...
Facade is useful when the caller should think in terms of one business action, but the system underneath still needs several subsystem calls to make that hap...
Decorator becomes useful when the base behavior is stable, but the way you wrap it keeps changing. That usually happens in systems where pricing, logging, va...
Adapter lets your application speak in its own language while wrapping external APIs that were never designed for your internal model. This is one of the mos...
Prototype is useful when creating a new object from scratch is expensive or when a predefined template should be copied and slightly adjusted. It is common i...
Builder is valuable when object construction is complex, optional fields are common, and you want the result to be immutable and readable. It is not useful f...
Abstract Factory is useful when you do not create just one object. You create a compatible family of objects that must vary together.
Factory Method solves a specific problem: object creation varies, but the surrounding workflow stays stable. That is common in backend systems that support m...
Singleton is the most overused pattern in Java. That does not make it useless. It means it must be applied carefully and only when a single shared instance i...
Most design patterns fail in production for a simple reason: the codebase violates basic design principles before the pattern is introduced. If responsibilit...
This series is written for engineers who already know Java syntax but want to improve how they structure code in real systems. The focus is not pattern memor...
This series covered many concurrency tools:
The biggest effect of modern Java concurrency is not that old primitives disappeared.
By 2025, Java backend teams often evaluate three broad concurrency styles:
ThreadLocal is one of those tools that feels convenient at first and architectural later.
Structured concurrency addresses a problem many asynchronous systems accumulate slowly:
Virtual threads are one of the biggest shifts in modern Java concurrency design.
Concurrency benchmarking is easy to get wrong in ways that still produce impressive-looking numbers.
When a concurrent system slows down, the real problem is often not “too little CPU.”
Thread dumps are excellent snapshots. JFR is better when you need a time-based story.
A thread dump can look overwhelming because it contains:
Deadlocks are one of the few concurrency failures that can leave a system looking alive while useful work has stopped.
Some concurrency bugs refuse to appear on command.
Not every concurrency test should be probabilistic.
Concurrent code is easy to test badly.
Service aggregation is where async composition stops being an academic API topic and becomes real backend architecture.
Plain Future and CompletableFuture both represent work that may finish later.
Async code does not eliminate the need for thread-pool design.
Async code without time budgets is just slower failure.
Async workflows are only readable if their failure behavior is readable too.
Most CompletableFuture code becomes readable or unreadable based on one thing:
CompletableFuture is where Java futures stop being just placeholders and start becoming a composition model.
Parallel streams are one of the easiest ways to add concurrency to Java code.
Parallel streams look deceptively simple:
Fork/Join performance problems are often self-inflicted.
Task granularity is where many Fork/Join workloads succeed or fail.
RecursiveAction is the sibling of RecursiveTask, but for tasks that do not return a value.
RecursiveTask<V> is the Fork/Join abstraction for work that returns a value.
Work stealing is the operational heart of Fork/Join.
The Fork/Join framework is not just “another executor.”
Thread pools solve real problems, but they also make it easy to package bad concurrency policy behind a neat API.
Executors fail quietly when nobody measures the right things.
Most thread pools are easier to operate once their threads stop looking anonymous.
An executor is not really production-ready until overload behavior is explicit.
In ThreadPoolExecutor, queue choice is not a secondary implementation detail.
IO-bound pool sizing is where teams often overlearn the CPU-bound rule and end up underprovisioned.
CPU-bound thread pool sizing is one of the few concurrency topics where “more parallelism” often becomes worse surprisingly quickly.
Sometimes the important question is not:
invokeAll and invokeAny are batch execution helpers on ExecutorService.
Cancellation in Java is cooperative.
Future is the simplest standard result handle for work that finishes later.
Scheduled executors are the executor framework’s answer to delayed and periodic work.
Single-thread executors look modest compared with larger pools, but they solve a very important class of concurrency problems:
Cached thread pools are the executor form of elastic optimism.
Executors.newFixedThreadPool(n) is one of the most common ways Java developers first adopt the executor framework.
Executor and ExecutorService are related, but they do not mean the same thing.
The executor framework is Java’s main answer to scalable task execution.
Creating a Thread manually is easy.
Work queues are one of the most common concurrency structures in backend systems.
In queue-based worker systems, one deceptively tricky question always appears:
Bounded queues are one of the most honest tools in concurrency design.
The producer-consumer pattern is one of the oldest concurrency patterns in software, and one of the easiest to overcomplicate when implemented manually.
SynchronousQueue is one of the most unintuitive queues in the JDK until the right mental model clicks.
DelayQueue is the blocking queue for one very specific question:
Most work queues are FIFO.
LinkedBlockingQueue is one of the most commonly used blocking queues in Java, often because it is easy to reach for and works well in many producer-consumer ...
ArrayBlockingQueue is the most explicit bounded queue in the core JDK.
BlockingQueue is one of the most practical concurrency abstractions in the JDK.
Most concurrent map discussions start and end with ConcurrentHashMap.
ConcurrentLinkedQueue is the standard non-blocking unbounded FIFO queue in the JDK.
CopyOnWriteArrayList is one of the most specialized collections in the concurrent collections family.
Using ConcurrentHashMap does not automatically make every map-related workflow correct.
ConcurrentHashMap is the default shared map choice for many Java services, and for good reason.
Once a collection becomes shared across threads, the next question is usually:
Ordinary Java collections are designed for single-threaded use unless you add an explicit concurrency strategy around them.
By this point in the module, the important thing is not memorizing six APIs.
CompletableFuture is often introduced as an async programming API.
Exchanger is one of the least-used coordination utilities in everyday Java application code.
Semaphores are naturally good at concurrency limiting.
Semaphores come in two broad conceptual forms:
Semaphore is the coordination primitive for permit-based access.
Phaser is the most flexible coordination utility in this part of the JDK.
The optional barrier action is what turns CyclicBarrier from a simple rendezvous tool into a phase-transition tool.
CyclicBarrier is the coordination primitive for repeated rendezvous.
Many coordination mistakes happen because developers choose a tool by API familiarity instead of by synchronization shape.
CountDownLatch is one of the simplest coordination tools in the JDK, and that simplicity is exactly why it stays useful.
Lock-free programming has real value.
Once you understand CAS loops, the next natural question is:
These three terms describe progress guarantees.
VarHandle is the modern low-level API behind a large part of Java’s atomic and memory-ordering machinery.
Atomic field updaters occupy an awkward but useful middle ground.
Counting looks trivial until many threads hit the same number.
Atomic counters are simple and effective.
The ABA problem is one of the classic edge cases in non-blocking algorithms.
Compare-and-set is the core move behind most atomic programming in Java.
These four atomic types cover a large percentage of practical application-level atomic use cases.
Atomic classes are the next major step after locks and volatile.
Java gives you several ways to coordinate shared mutable state.
StampedLock is one of the easiest concurrency tools to overestimate.
StampedLock was added for advanced cases where read-mostly access patterns may benefit from something lighter than ordinary read-lock coordination.
Read-write locks introduce a subtle topic that ordinary exclusive locks do not: moving between read and write modes.
ReentrantReadWriteLock is the standard JDK implementation of ReadWriteLock.
Not all shared state has the same access pattern.
Producer-consumer is one of the best examples for why explicit conditions exist.
One of the biggest practical advantages of Condition over monitor-based wait/notify is that one lock can have more than one wait queue.
Monitor-based wait and notify are powerful, but they become hard to maintain when one shared state has several reasons to wait.
A thread blocked on lock acquisition is still consuming scheduling attention even if useful business progress is zero.
Some code paths should not wait indefinitely for a lock.
Fairness sounds like an obvious good, but in locking it comes with real cost.
ReentrantLock is the most widely used explicit lock in Java.
Java already had synchronized, so the Lock interface was not added to replace locking in general.
Singletons are often discussed as a design-pattern topic.
final fields matter for more than preventing reassignment.
Creating an object correctly is only part of concurrent correctness.
One of the strongest concurrency strategies is not a lock, atomic, or volatile field.
Mutable and immutable classes are not just two object-modeling styles.
It is easy to say “make it immutable.”
The easiest shared mutable state to make thread-safe is the state you never mutate.
Most Java concurrency design choices in everyday backend code come down to three tool families:
volatile and synchronized are often presented as if they were two competing shortcuts for the same job.
Many Java concurrency bugs come from one mistaken belief:
The previous article explained what volatile is and what it is not.
volatile is one of the most misunderstood keywords in Java concurrency.
Sometimes a system performs acceptably at moderate load and then falls apart sharply instead of degrading gradually.
Some concurrency failures are correctness bugs. Others are performance failures caused by hardware-level contention.
Not all concurrency failures come from incorrect locking.
Priority inversion happens when more important work waits because less important work is holding a resource it needs.
Starvation happens when a thread is not blocked forever by one circular wait, but still fails to make enough progress because other work keeps getting prefer...
Deadlock means threads are stuck and not moving.
Deadlock is one of the clearest concurrency failures because the system stops making progress even though the process is still alive.
One of the most subtle forms of unsafe publication happens when an object exposes itself before construction is complete.
Not every concurrency bug looks like two threads fighting over a counter.
Lost updates are the concrete business symptom of many race conditions.
Some concurrency bugs are not about two threads writing at the same time.
Read-modify-write is another core race pattern.
Check-then-act is one of the most common race patterns in Java.
Module 4 begins with the most common class of concurrency failure: race conditions.
Low-level monitor coordination is useful to learn because it exposes the core rules of Java concurrency clearly.
Indefinite waiting is sometimes correct. Sometimes it is not.
Low-level monitor coordination is powerful enough to be correct and dangerous enough to be fragile.
Producer-consumer is one of the most useful patterns for understanding monitor-based coordination.
The guarded blocks pattern is the cleanest way to think about low-level monitor waiting.
Spurious wakeups are one of the reasons Java requires wait() to be guarded by a loop.
This rule is simple and non-negotiable: wait() must be used inside a loop that re-checks the condition.
wait, notify, and notifyAll are some of the oldest and most misunderstood coordination tools in Java.
Java intrinsic locks are reentrant. That means a thread that already owns a monitor may enter another synchronized section guarded by the same monitor again ...
Many developers think synchronized is only about “one thread at a time.” That is incomplete.
Mutual exclusion is one of the most basic goals of locking: only one thread should execute a critical section at a time.
You do not need to memorize JVM object-header layouts to write good Java application code. But it helps to know that monitor ownership is not abstract magic....
If synchronized is the syntax, the monitor is the underlying coordination mechanism.
synchronized is the first real shared-state protection mechanism most Java developers use. It is simple enough to learn quickly and powerful enough to build ...
Knowing that interruption exists is not enough. Long-running tasks need to be designed so interruption actually works in practice.
Java does not have a safe general-purpose “kill this thread now” operation for normal application code. Instead, it uses interruption as a cooperative cancel...
Daemon threads are easy to misunderstand. Many people think they are just “background threads.” The more important truth is that daemon status changes JVM sh...
join is one of the simplest thread-coordination methods in Java. It is also more important than it looks because it is not only a waiting primitive, it is al...
sleep, yield, and interruption are often learned together. That makes sense because they all affect thread progression, but they solve very different problems.
Thread priority is one of the first Java concurrency tools people discover and one of the first they overestimate.
Unnamed threads are a tax on debugging. They make incidents slower to diagnose and make thread dumps far harder to interpret than they need to be.
Runnable is good for work that just needs to run. Callable exists for work that needs to return something meaningful.
Runnable looks simple enough to ignore. That is a mistake.
Creating a thread directly is one of the first concurrency tools Java gives you. It is also one of the first tools teams outgrow in production systems.
Atomicity, visibility, and ordering are three different concerns. Many concurrency bugs happen because developers fix one and assume the other two are automa...
If you remember only one formal concurrency concept from the Java Memory Model, remember happens-before.
The Java Memory Model, or JMM, defines what one thread is allowed to observe about actions performed by another thread.
Many Java concurrency bugs begin with one wrong assumption: if one thread updates a variable, another thread will immediately see the new value.
Most Java concurrency problems are really shared-state problems. When multiple threads can touch the same mutable object, correctness becomes difficult quick...
Threads are useful, but they are not free. If you treat them like cheap magic, your system will waste CPU, memory, and latency budget just coordinating execu...
If you do not understand thread states, thread dumps will look like random noise. You will see RUNNABLE, WAITING, or BLOCKED and still have no idea whether t...
Concurrency, parallelism, and asynchrony are related, but they are not the same thing. Teams often mix them together and then design the wrong system for the...
Java developers often use the words process, thread, and task loosely. That creates design confusion early: people choose an executor when they really mean a...
Concurrency is hard because it forces you to optimize several things at once: correctness, latency, throughput, resource usage, and failure handling.
This series is designed as a full Java multithreading and concurrency curriculum. The goal is not to collect disconnected interview notes. The goal is to bui...
This guide explains the intuition, optimized approach, and Java implementation for sort array by parity in java, with practical tips for interviews and produ...
This guide explains the intuition, optimized approach, and Java implementation for maximum subarray in java (kadane algorithm), with practical tips for inter...
Given a string containing only ()[]{}, return true if brackets are valid. A valid string must close in correct order and with correct bracket type.
Given an array nums of size n where values are in range [1, n], some numbers appear twice and others are missing. Return all missing numbers.
This guide explains the intuition, optimized approach, and Java implementation for move zeroes in java (stable in-place), with practical tips for interviews ...
Given an integer array where every value appears exactly twice except one value, return the value that appears once.
This guide explains the intuition, optimized approach, and Java implementation for maximum depth of binary tree in java, with practical tips for interviews a...
This guide explains the intuition, optimized approach, and Java implementation for remove duplicates from sorted list ii in java, with practical tips for int...
Given a sorted array, remove duplicates in-place so each unique value appears once. Return the number of unique elements.
Given a string, repeatedly remove adjacent equal characters until no such pair remains.
This guide explains the intuition, optimized approach, and Java implementation for palindrome number in java (without string conversion), with practical tips...
Given the head of a singly linked list, return its middle node. If the list has two middle nodes, return the second middle.
This guide explains the intuition, optimized approach, and Java implementation for longest substring without repeating characters in java, with practical tip...
This guide explains the intuition, optimized approach, and Java implementation for linked list cycle ii in java (find cycle start), with practical tips for i...
This guide explains the intuition, optimized approach, and Java implementation for first missing positive in java, with practical tips for interviews and pro...
This guide explains the intuition, optimized approach, and Java implementation for find first and last position of element in sorted array, with practical ti...
Given a rotated sorted array with distinct values, find the minimum element in O(log n).
This guide explains the intuition, optimized approach, and Java implementation for remove linked list elements in java, with practical tips for interviews an...
Given a sorted linked list, remove duplicate nodes so each value appears exactly once.
Given an array height, pick two indices i and j to form a container. Maximize area:
This guide explains the intuition, optimized approach, and Java implementation for binary search in java (iterative and recursive), with practical tips for i...
This guide explains the intuition, optimized approach, and Java implementation for add two numbers represented as linked list, with practical tips for interv...
This guide explains the intuition, optimized approach, and Java implementation for detect a loop in linked list (floyd cycle detection), with practical tips ...
Reverse a singly linked list using recursion.
This guide explains the intuition, optimized approach, and Java implementation for reverse linked list iteratively in java, with practical tips for interview...
This deep dive explains the problem model, concurrency contract, Java implementation, and real-world caveats you should know before using this pattern in pro...
Double-checked locking provides lazy initialization with lower synchronization overhead after initialization.
CyclicBarrier lets a fixed number of threads wait until all participants reach the same synchronization point.
A Semaphore controls how many threads can access a shared resource at the same time.
This is a learning-oriented implementation to understand worker threads, queueing, and task execution flow.
This post explains how a latch works internally using a simplified custom implementation.
BlockingQueue is a thread-safe queue from java.util.concurrent used heavily in producer-consumer systems.
This example validates that bean fields are not null using a custom class-level annotation.
Interview-style concurrency problem: ensure threads print in strict round-robin sequence.
invokeAll submits a collection of Callable tasks and waits until all complete.
DelayQueue is a specialized blocking queue where elements become available only after a delay expires.
Enums model a fixed set of constants with type safety and encapsulated behavior.
Varargs (...) lets a method accept zero or more arguments of the same type.
This series covered many concurrency tools:
The biggest effect of modern Java concurrency is not that old primitives disappeared.
By 2025, Java backend teams often evaluate three broad concurrency styles:
ThreadLocal is one of those tools that feels convenient at first and architectural later.
Structured concurrency addresses a problem many asynchronous systems accumulate slowly:
Virtual threads are one of the biggest shifts in modern Java concurrency design.
Concurrency benchmarking is easy to get wrong in ways that still produce impressive-looking numbers.
When a concurrent system slows down, the real problem is often not “too little CPU.”
Thread dumps are excellent snapshots. JFR is better when you need a time-based story.
A thread dump can look overwhelming because it contains:
Deadlocks are one of the few concurrency failures that can leave a system looking alive while useful work has stopped.
Some concurrency bugs refuse to appear on command.
Not every concurrency test should be probabilistic.
Concurrent code is easy to test badly.
Service aggregation is where async composition stops being an academic API topic and becomes real backend architecture.
Plain Future and CompletableFuture both represent work that may finish later.
Async code does not eliminate the need for thread-pool design.
Async code without time budgets is just slower failure.
Async workflows are only readable if their failure behavior is readable too.
Most CompletableFuture code becomes readable or unreadable based on one thing:
CompletableFuture is where Java futures stop being just placeholders and start becoming a composition model.
Parallel streams are one of the easiest ways to add concurrency to Java code.
Parallel streams look deceptively simple:
Fork/Join performance problems are often self-inflicted.
Task granularity is where many Fork/Join workloads succeed or fail.
RecursiveAction is the sibling of RecursiveTask, but for tasks that do not return a value.
RecursiveTask<V> is the Fork/Join abstraction for work that returns a value.
Work stealing is the operational heart of Fork/Join.
The Fork/Join framework is not just “another executor.”
Thread pools solve real problems, but they also make it easy to package bad concurrency policy behind a neat API.
Executors fail quietly when nobody measures the right things.
Most thread pools are easier to operate once their threads stop looking anonymous.
An executor is not really production-ready until overload behavior is explicit.
In ThreadPoolExecutor, queue choice is not a secondary implementation detail.
IO-bound pool sizing is where teams often overlearn the CPU-bound rule and end up underprovisioned.
CPU-bound thread pool sizing is one of the few concurrency topics where “more parallelism” often becomes worse surprisingly quickly.
Sometimes the important question is not:
invokeAll and invokeAny are batch execution helpers on ExecutorService.
Cancellation in Java is cooperative.
Future is the simplest standard result handle for work that finishes later.
Scheduled executors are the executor framework’s answer to delayed and periodic work.
Single-thread executors look modest compared with larger pools, but they solve a very important class of concurrency problems:
Cached thread pools are the executor form of elastic optimism.
Executors.newFixedThreadPool(n) is one of the most common ways Java developers first adopt the executor framework.
Executor and ExecutorService are related, but they do not mean the same thing.
The executor framework is Java’s main answer to scalable task execution.
Creating a Thread manually is easy.
Work queues are one of the most common concurrency structures in backend systems.
In queue-based worker systems, one deceptively tricky question always appears:
Bounded queues are one of the most honest tools in concurrency design.
The producer-consumer pattern is one of the oldest concurrency patterns in software, and one of the easiest to overcomplicate when implemented manually.
SynchronousQueue is one of the most unintuitive queues in the JDK until the right mental model clicks.
DelayQueue is the blocking queue for one very specific question:
Most work queues are FIFO.
LinkedBlockingQueue is one of the most commonly used blocking queues in Java, often because it is easy to reach for and works well in many producer-consumer ...
ArrayBlockingQueue is the most explicit bounded queue in the core JDK.
BlockingQueue is one of the most practical concurrency abstractions in the JDK.
Most concurrent map discussions start and end with ConcurrentHashMap.
ConcurrentLinkedQueue is the standard non-blocking unbounded FIFO queue in the JDK.
CopyOnWriteArrayList is one of the most specialized collections in the concurrent collections family.
Using ConcurrentHashMap does not automatically make every map-related workflow correct.
ConcurrentHashMap is the default shared map choice for many Java services, and for good reason.
Once a collection becomes shared across threads, the next question is usually:
Ordinary Java collections are designed for single-threaded use unless you add an explicit concurrency strategy around them.
By this point in the module, the important thing is not memorizing six APIs.
CompletableFuture is often introduced as an async programming API.
Exchanger is one of the least-used coordination utilities in everyday Java application code.
Semaphores are naturally good at concurrency limiting.
Semaphores come in two broad conceptual forms:
Semaphore is the coordination primitive for permit-based access.
Phaser is the most flexible coordination utility in this part of the JDK.
The optional barrier action is what turns CyclicBarrier from a simple rendezvous tool into a phase-transition tool.
CyclicBarrier is the coordination primitive for repeated rendezvous.
Many coordination mistakes happen because developers choose a tool by API familiarity instead of by synchronization shape.
CountDownLatch is one of the simplest coordination tools in the JDK, and that simplicity is exactly why it stays useful.
Lock-free programming has real value.
Once you understand CAS loops, the next natural question is:
These three terms describe progress guarantees.
VarHandle is the modern low-level API behind a large part of Java’s atomic and memory-ordering machinery.
Atomic field updaters occupy an awkward but useful middle ground.
Counting looks trivial until many threads hit the same number.
Atomic counters are simple and effective.
The ABA problem is one of the classic edge cases in non-blocking algorithms.
Compare-and-set is the core move behind most atomic programming in Java.
These four atomic types cover a large percentage of practical application-level atomic use cases.
Atomic classes are the next major step after locks and volatile.
Java gives you several ways to coordinate shared mutable state.
StampedLock is one of the easiest concurrency tools to overestimate.
StampedLock was added for advanced cases where read-mostly access patterns may benefit from something lighter than ordinary read-lock coordination.
Read-write locks introduce a subtle topic that ordinary exclusive locks do not: moving between read and write modes.
ReentrantReadWriteLock is the standard JDK implementation of ReadWriteLock.
Not all shared state has the same access pattern.
Producer-consumer is one of the best examples for why explicit conditions exist.
One of the biggest practical advantages of Condition over monitor-based wait/notify is that one lock can have more than one wait queue.
Monitor-based wait and notify are powerful, but they become hard to maintain when one shared state has several reasons to wait.
A thread blocked on lock acquisition is still consuming scheduling attention even if useful business progress is zero.
Some code paths should not wait indefinitely for a lock.
Fairness sounds like an obvious good, but in locking it comes with real cost.
ReentrantLock is the most widely used explicit lock in Java.
Java already had synchronized, so the Lock interface was not added to replace locking in general.
Singletons are often discussed as a design-pattern topic.
final fields matter for more than preventing reassignment.
Creating an object correctly is only part of concurrent correctness.
One of the strongest concurrency strategies is not a lock, atomic, or volatile field.
Mutable and immutable classes are not just two object-modeling styles.
It is easy to say “make it immutable.”
The easiest shared mutable state to make thread-safe is the state you never mutate.
Most Java concurrency design choices in everyday backend code come down to three tool families:
volatile and synchronized are often presented as if they were two competing shortcuts for the same job.
Many Java concurrency bugs come from one mistaken belief:
The previous article explained what volatile is and what it is not.
volatile is one of the most misunderstood keywords in Java concurrency.
Sometimes a system performs acceptably at moderate load and then falls apart sharply instead of degrading gradually.
Some concurrency failures are correctness bugs. Others are performance failures caused by hardware-level contention.
Not all concurrency failures come from incorrect locking.
Priority inversion happens when more important work waits because less important work is holding a resource it needs.
Starvation happens when a thread is not blocked forever by one circular wait, but still fails to make enough progress because other work keeps getting prefer...
Deadlock means threads are stuck and not moving.
Deadlock is one of the clearest concurrency failures because the system stops making progress even though the process is still alive.
One of the most subtle forms of unsafe publication happens when an object exposes itself before construction is complete.
Not every concurrency bug looks like two threads fighting over a counter.
Lost updates are the concrete business symptom of many race conditions.
Some concurrency bugs are not about two threads writing at the same time.
Read-modify-write is another core race pattern.
Check-then-act is one of the most common race patterns in Java.
Module 4 begins with the most common class of concurrency failure: race conditions.
Low-level monitor coordination is useful to learn because it exposes the core rules of Java concurrency clearly.
Indefinite waiting is sometimes correct. Sometimes it is not.
Low-level monitor coordination is powerful enough to be correct and dangerous enough to be fragile.
Producer-consumer is one of the most useful patterns for understanding monitor-based coordination.
The guarded blocks pattern is the cleanest way to think about low-level monitor waiting.
Spurious wakeups are one of the reasons Java requires wait() to be guarded by a loop.
This rule is simple and non-negotiable: wait() must be used inside a loop that re-checks the condition.
wait, notify, and notifyAll are some of the oldest and most misunderstood coordination tools in Java.
Java intrinsic locks are reentrant. That means a thread that already owns a monitor may enter another synchronized section guarded by the same monitor again ...
Many developers think synchronized is only about “one thread at a time.” That is incomplete.
Mutual exclusion is one of the most basic goals of locking: only one thread should execute a critical section at a time.
You do not need to memorize JVM object-header layouts to write good Java application code. But it helps to know that monitor ownership is not abstract magic....
If synchronized is the syntax, the monitor is the underlying coordination mechanism.
synchronized is the first real shared-state protection mechanism most Java developers use. It is simple enough to learn quickly and powerful enough to build ...
Knowing that interruption exists is not enough. Long-running tasks need to be designed so interruption actually works in practice.
Java does not have a safe general-purpose “kill this thread now” operation for normal application code. Instead, it uses interruption as a cooperative cancel...
Daemon threads are easy to misunderstand. Many people think they are just “background threads.” The more important truth is that daemon status changes JVM sh...
join is one of the simplest thread-coordination methods in Java. It is also more important than it looks because it is not only a waiting primitive, it is al...
sleep, yield, and interruption are often learned together. That makes sense because they all affect thread progression, but they solve very different problems.
Thread priority is one of the first Java concurrency tools people discover and one of the first they overestimate.
Unnamed threads are a tax on debugging. They make incidents slower to diagnose and make thread dumps far harder to interpret than they need to be.
Runnable is good for work that just needs to run. Callable exists for work that needs to return something meaningful.
Runnable looks simple enough to ignore. That is a mistake.
Creating a thread directly is one of the first concurrency tools Java gives you. It is also one of the first tools teams outgrow in production systems.
Atomicity, visibility, and ordering are three different concerns. Many concurrency bugs happen because developers fix one and assume the other two are automa...
If you remember only one formal concurrency concept from the Java Memory Model, remember happens-before.
The Java Memory Model, or JMM, defines what one thread is allowed to observe about actions performed by another thread.
Many Java concurrency bugs begin with one wrong assumption: if one thread updates a variable, another thread will immediately see the new value.
Most Java concurrency problems are really shared-state problems. When multiple threads can touch the same mutable object, correctness becomes difficult quick...
Threads are useful, but they are not free. If you treat them like cheap magic, your system will waste CPU, memory, and latency budget just coordinating execu...
If you do not understand thread states, thread dumps will look like random noise. You will see RUNNABLE, WAITING, or BLOCKED and still have no idea whether t...
Concurrency, parallelism, and asynchrony are related, but they are not the same thing. Teams often mix them together and then design the wrong system for the...
Java developers often use the words process, thread, and task loosely. That creates design confusion early: people choose an executor when they really mean a...
Concurrency is hard because it forces you to optimize several things at once: correctness, latency, throughput, resource usage, and failure handling.
This series is designed as a full Java multithreading and concurrency curriculum. The goal is not to collect disconnected interview notes. The goal is to bui...
This deep dive explains the problem model, concurrency contract, Java implementation, and real-world caveats you should know before using this pattern in pro...
Double-checked locking provides lazy initialization with lower synchronization overhead after initialization.
CyclicBarrier lets a fixed number of threads wait until all participants reach the same synchronization point.
A Semaphore controls how many threads can access a shared resource at the same time.
This is a learning-oriented implementation to understand worker threads, queueing, and task execution flow.
This post explains how a latch works internally using a simplified custom implementation.
BlockingQueue is a thread-safe queue from java.util.concurrent used heavily in producer-consumer systems.
Interview-style concurrency problem: ensure threads print in strict round-robin sequence.
invokeAll submits a collection of Callable tasks and waits until all complete.
DelayQueue is a specialized blocking queue where elements become available only after a delay expires.
A prototype agent that works in a demo is easy. A production agent that is safe, reliable, observable, and cost-controlled is hard.
Agentic AI systems do more than generate one response. They decompose goals, choose actions, call tools, inspect outcomes, and iterate until completion or st...
Embedding models convert text (or other modalities) into vectors that power retrieval, clustering, semantic matching, and recommendation.
Vector databases are central to modern RAG systems, but many implementations fail because teams treat them as storage instead of retrieval engines.
This final article combines the January series into one practical blueprint. Production ML success requires coordinated decisions across data, modeling, depl...
AI quality is not just prediction quality. A model can be accurate and still unfair, privacy-invasive, insecure, or unsafe in deployment.
Offline model quality improvements are useful, but they are not proof of business impact. A model can increase AUC and still reduce conversion, increase comp...
A model that performed well on launch day can fail silently two weeks later. In production, distributions move, user behavior evolves, adversaries adapt, and...
A production model is useful only when it can make decisions in the right place, at the right time, with predictable reliability.
Most production ML regressions are not caused by model architecture. They are caused by feature mismatch: training saw one definition, serving used another.
A model that works once in a notebook is a prototype. A model that can be retrained, validated, deployed, monitored, rolled back, and audited is a production...
RAG is one of the most practical ways to make LLM answers more factual, auditable, and domain-aware. Instead of relying only on model memory, RAG injects ret...
Prompt engineering in production is about behavior control, not prose quality. A prompt is an interface contract between product requirements and model behav...
LLM applications look simple from API perspective but involve multiple layers of trade-offs. Strong products require understanding tokenization, pretraining ...
Transformers dominate many NLP benchmarks, but recurrent models still matter in latency-sensitive and resource-constrained sequential tasks. Understanding RN...
Computer vision systems convert pixels into structured outputs such as labels, boxes, masks, or embeddings. CNNs remain foundational in many practical vision...
Transformers are the architecture behind modern LLMs, code models, rerankers, and many multimodal systems. They replaced recurrent-heavy NLP because they mod...
NLP systems convert language into representations models can reason over. Good results depend on robust data preparation, task framing, and evaluation discip...
Recommendation systems are not one model. They are multi-stage decision pipelines balancing relevance, diversity, freshness, fairness, and latency.
Forecasting predicts future values from historical temporal patterns. It is central to inventory planning, staffing, demand management, and capacity control.
Anomaly detection is used when rare harmful events matter more than average behavior. Examples include payment fraud, infrastructure incidents, insider abuse...
High-dimensional data introduces noise, sparsity, and computational cost. Dimensionality reduction can improve model stability, speed, and interpretability w...
Clustering finds structure in unlabeled data. It is widely used for customer segmentation, pattern discovery, exploratory analysis, and anomaly surfacing.
Support Vector Machines (SVM) are still useful in many medium-scale, high-dimensional classification problems. They provide strong geometry-based decision bo...
Gradient boosting is one of the highest-performing approaches for tabular ML. Its power comes from sequentially correcting residual errors rather than averag...
Random forest is often the fastest way to get a strong tabular baseline. It reduces variance of decision trees through bagging and feature randomness.
Decision trees are one of the most practical ML models for tabular data. They are intuitive, flexible, and strong baselines for both classification and regre...
Training accuracy can always be pushed up with enough complexity. Real ML quality is measured on unseen data.
If your split strategy is wrong, every model comparison is unreliable. Cross-validation is not just a data science ritual; it is how you estimate future perf...
Most model failures in production are not training failures. They are evaluation failures.
Model quality on tabular data is often decided by features, not model family. A disciplined feature process can turn an average model into a strong productio...
Most ML training is optimization. You define a loss function and adjust parameters to reduce it.
Linear regression predicts continuous values. Classification problems need class probabilities and decisions.
Linear regression is often taught as a beginner model. In practice, it is also a serious production baseline and, in many cases, a final model.
Most people start AI/ML by jumping into a framework and training a model. That is usually the fastest path to confusion.
A prototype agent that works in a demo is easy. A production agent that is safe, reliable, observable, and cost-controlled is hard.
Agentic AI systems do more than generate one response. They decompose goals, choose actions, call tools, inspect outcomes, and iterate until completion or st...
Embedding models convert text (or other modalities) into vectors that power retrieval, clustering, semantic matching, and recommendation.
Vector databases are central to modern RAG systems, but many implementations fail because teams treat them as storage instead of retrieval engines.
This final article combines the January series into one practical blueprint. Production ML success requires coordinated decisions across data, modeling, depl...
AI quality is not just prediction quality. A model can be accurate and still unfair, privacy-invasive, insecure, or unsafe in deployment.
Offline model quality improvements are useful, but they are not proof of business impact. A model can increase AUC and still reduce conversion, increase comp...
A model that performed well on launch day can fail silently two weeks later. In production, distributions move, user behavior evolves, adversaries adapt, and...
A production model is useful only when it can make decisions in the right place, at the right time, with predictable reliability.
Most production ML regressions are not caused by model architecture. They are caused by feature mismatch: training saw one definition, serving used another.
A model that works once in a notebook is a prototype. A model that can be retrained, validated, deployed, monitored, rolled back, and audited is a production...
RAG is one of the most practical ways to make LLM answers more factual, auditable, and domain-aware. Instead of relying only on model memory, RAG injects ret...
Prompt engineering in production is about behavior control, not prose quality. A prompt is an interface contract between product requirements and model behav...
LLM applications look simple from API perspective but involve multiple layers of trade-offs. Strong products require understanding tokenization, pretraining ...
Transformers dominate many NLP benchmarks, but recurrent models still matter in latency-sensitive and resource-constrained sequential tasks. Understanding RN...
Computer vision systems convert pixels into structured outputs such as labels, boxes, masks, or embeddings. CNNs remain foundational in many practical vision...
Transformers are the architecture behind modern LLMs, code models, rerankers, and many multimodal systems. They replaced recurrent-heavy NLP because they mod...
NLP systems convert language into representations models can reason over. Good results depend on robust data preparation, task framing, and evaluation discip...
Recommendation systems are not one model. They are multi-stage decision pipelines balancing relevance, diversity, freshness, fairness, and latency.
Forecasting predicts future values from historical temporal patterns. It is central to inventory planning, staffing, demand management, and capacity control.
Anomaly detection is used when rare harmful events matter more than average behavior. Examples include payment fraud, infrastructure incidents, insider abuse...
High-dimensional data introduces noise, sparsity, and computational cost. Dimensionality reduction can improve model stability, speed, and interpretability w...
Clustering finds structure in unlabeled data. It is widely used for customer segmentation, pattern discovery, exploratory analysis, and anomaly surfacing.
Support Vector Machines (SVM) are still useful in many medium-scale, high-dimensional classification problems. They provide strong geometry-based decision bo...
Gradient boosting is one of the highest-performing approaches for tabular ML. Its power comes from sequentially correcting residual errors rather than averag...
Random forest is often the fastest way to get a strong tabular baseline. It reduces variance of decision trees through bagging and feature randomness.
Decision trees are one of the most practical ML models for tabular data. They are intuitive, flexible, and strong baselines for both classification and regre...
Training accuracy can always be pushed up with enough complexity. Real ML quality is measured on unseen data.
If your split strategy is wrong, every model comparison is unreliable. Cross-validation is not just a data science ritual; it is how you estimate future perf...
Most model failures in production are not training failures. They are evaluation failures.
Model quality on tabular data is often decided by features, not model family. A disciplined feature process can turn an average model into a strong productio...
Most ML training is optimization. You define a loss function and adjust parameters to reduce it.
Linear regression predicts continuous values. Classification problems need class probabilities and decisions.
Linear regression is often taught as a beginner model. In practice, it is also a serious production baseline and, in many cases, a final model.
Most people start AI/ML by jumping into a framework and training a model. That is usually the fastest path to confusion.
Intervals problems are mostly about ordering and overlap rules. Once sorted, many become simple linear scans.
Use heaps when you need repeated access to the smallest or largest element under updates. Java provides this via PriorityQueue.
Monotonic deque extends monotonic-stack thinking to moving windows. It gives fast max/min queries while the window slides.
Monotonic stack helps find next/previous greater or smaller elements in linear time. It avoids repeated backward or forward scans.
Binary search is not just for finding a value in a sorted array. It is a decision pattern over monotonic spaces.
Hash-based patterns are the default when you need fast membership checks, counts, or complement lookups. This pattern often converts nested-loop logic into l...
Prefix Sum is one of the highest-leverage DSA patterns. It converts repeated range computations from repeated work into constant-time lookups after linear pr...
Sliding Window is a focused form of the Two Pointers technique. If Two Pointers teaches movement strategy, Sliding Window teaches stateful range management.
Two Pointers is one of the most effective techniques for turning brute-force array/string solutions into linear-time solutions.
This guide explains the intuition, optimized approach, and Java implementation for sort array by parity in java, with practical tips for interviews and produ...
This guide explains the intuition, optimized approach, and Java implementation for maximum subarray in java (kadane algorithm), with practical tips for inter...
Given a string containing only ()[]{}, return true if brackets are valid. A valid string must close in correct order and with correct bracket type.
Given an array nums of size n where values are in range [1, n], some numbers appear twice and others are missing. Return all missing numbers.
This guide explains the intuition, optimized approach, and Java implementation for move zeroes in java (stable in-place), with practical tips for interviews ...
Given an integer array where every value appears exactly twice except one value, return the value that appears once.
This guide explains the intuition, optimized approach, and Java implementation for maximum depth of binary tree in java, with practical tips for interviews a...
This guide explains the intuition, optimized approach, and Java implementation for remove duplicates from sorted list ii in java, with practical tips for int...
Given a sorted array, remove duplicates in-place so each unique value appears once. Return the number of unique elements.
Given a string, repeatedly remove adjacent equal characters until no such pair remains.
This guide explains the intuition, optimized approach, and Java implementation for palindrome number in java (without string conversion), with practical tips...
Given the head of a singly linked list, return its middle node. If the list has two middle nodes, return the second middle.
This guide explains the intuition, optimized approach, and Java implementation for longest substring without repeating characters in java, with practical tip...
This guide explains the intuition, optimized approach, and Java implementation for linked list cycle ii in java (find cycle start), with practical tips for i...
This guide explains the intuition, optimized approach, and Java implementation for first missing positive in java, with practical tips for interviews and pro...
This guide explains the intuition, optimized approach, and Java implementation for find first and last position of element in sorted array, with practical ti...
Given a rotated sorted array with distinct values, find the minimum element in O(log n).
This guide explains the intuition, optimized approach, and Java implementation for remove linked list elements in java, with practical tips for interviews an...
Given a sorted linked list, remove duplicate nodes so each value appears exactly once.
Given an array height, pick two indices i and j to form a container. Maximize area:
This guide explains the intuition, optimized approach, and Java implementation for binary search in java (iterative and recursive), with practical tips for i...
This guide explains the intuition, optimized approach, and Java implementation for add two numbers represented as linked list, with practical tips for interv...
This guide explains the intuition, optimized approach, and Java implementation for detect a loop in linked list (floyd cycle detection), with practical tips ...
Reverse a singly linked list using recursion.
This guide explains the intuition, optimized approach, and Java implementation for reverse linked list iteratively in java, with practical tips for interview...
The hardest part of design patterns is not implementation. It is choosing the right pattern and stopping before abstraction becomes ceremony.
Chain of Responsibility is attractive whenever one big validator starts turning into a wall of conditionals. The promise is simple: separate each rule, keep ...
State becomes useful when an object’s behavior changes meaningfully based on its current lifecycle stage. Without it, classes often fill up with conditionals...
Template Method is a good fit when the overall algorithm is stable, but one or more steps vary by subtype. It is especially common in parsing and import work...
Command turns an action into an object. That sounds simple, but it enables powerful capabilities:
Strategy is one of the most useful patterns in Java because many business rules are really just interchangeable algorithms selected at runtime.
Observer is about decoupling publishers from subscribers. It works well when one state change must trigger multiple downstream reactions that should not be h...
Teams often discover Proxy accidentally. They add authorization, then caching, then maybe rate limiting, and suddenly one object is standing between callers ...
Facade is useful when the caller should think in terms of one business action, but the system underneath still needs several subsystem calls to make that hap...
Decorator becomes useful when the base behavior is stable, but the way you wrap it keeps changing. That usually happens in systems where pricing, logging, va...
Adapter lets your application speak in its own language while wrapping external APIs that were never designed for your internal model. This is one of the mos...
Prototype is useful when creating a new object from scratch is expensive or when a predefined template should be copied and slightly adjusted. It is common i...
Builder is valuable when object construction is complex, optional fields are common, and you want the result to be immutable and readable. It is not useful f...
Abstract Factory is useful when you do not create just one object. You create a compatible family of objects that must vary together.
Factory Method solves a specific problem: object creation varies, but the surrounding workflow stays stable. That is common in backend systems that support m...
Singleton is the most overused pattern in Java. That does not make it useless. It means it must be applied carefully and only when a single shared instance i...
Most design patterns fail in production for a simple reason: the codebase violates basic design principles before the pattern is introduced. If responsibilit...
This series is written for engineers who already know Java syntax but want to improve how they structure code in real systems. The focus is not pattern memor...
This guide provides a clean, repeatable setup flow, verification steps, and common pitfalls to avoid in real environments.
Use this when Maven is installed manually (tar/zip) and not via apt.
When developing locally, you often need different settings than production (URL, analytics, Disqus, etc.).