Java Omnibus
OOAD & Architecture / Concurrency Patterns / Java Concurrency vs Design Patterns
Comparison GoF Concurrency Java
Concurrency Patterns

Concurrency patterns are still design patterns, but they solve a different class of pressure: time, contention, and coordination.

Many teams learn GoF patterns first and then approach concurrency as if it were just an API layer. In reality, concurrency patterns answer different questions. Strategy, Adapter, and Facade clarify variation and structure. Concurrency patterns clarify ownership, work scheduling, communication, contention, and safe state change across overlapping execution.

Why This Topic Matters

Why it matters in real Java systems

A Java team can have elegant object structure and still fail under load because requests pile up on shared state or blocking IO. Knowing how concurrency patterns differ from classic design patterns helps teams avoid expecting the wrong tool to solve the wrong class of problem.

Core Explanation

The main design idea

Classic design patterns often shape static structure and object collaboration. Concurrency patterns shape dynamic behavior under time pressure: when work runs, who owns mutable state, how callers coordinate with workers, and how bounded resources are protected. Both belong to design. They simply operate under different stresses.

A useful mental model is this: GoF patterns help code stay understandable as structure grows. Concurrency patterns help code stay correct and resilient as overlapping execution grows.

Concept Breakdown

Key ideas to keep in mind

Concept

Structure vs timing

GoF patterns mostly clarify structure; concurrency patterns clarify what happens when work overlaps.

Concept

Variation vs ownership

Strategy can choose an algorithm, but it will not tell you who owns the state that algorithm touches.

Concept

Coordination as design

Queues, monitors, reactors, and pools are architecture choices around execution, not just libraries.

Comparison table

Comparison table

Question Classic design pattern lens Concurrency pattern lens
How do responsibilities collaborate?Use Strategy, Facade, Adapter, Observer, and othersAsk whether collaboration is synchronous, queued, evented, or isolated by worker ownership
How do we protect mutable state?Usually not the primary concernUse monitors, message passing, confinement, or immutability
How is capacity managed?Rarely explicitThread pools, bounded queues, reactor loops, and backpressure matter directly
What fails under load?Structural coupling and responsibility driftRaces, deadlocks, starvation, queue blowups, timeout cascades
Java Example

Java example in the Order Management domain

Java example: a pattern boundary around execution
package org.javaomnibus.notifications;

public final class NotificationDispatcher {
    private final Executor executor;
    private final NotificationSender sender;

    public NotificationDispatcher(Executor executor, NotificationSender sender) {
        this.executor = executor;
        this.sender = sender;
    }

    public void dispatch(Notification notification) {
        executor.execute(() -> sender.send(notification));
    }
}
Code Walkthrough

Step by step

  1. The sender could still use GoF patterns internally, but the bigger design question here is execution ownership.
  2. Once the dispatch is asynchronous, queueing, saturation, retries, and observability become part of the design.
  3. That is the difference this page is making explicit.
  4. Concurrency patterns rarely replace classic patterns; they usually complement them.
Real-World Usage

Where this helps in practice

  • Teaching experienced OO developers how concurrency changes design concerns
  • Architecture reviews where code structure looks clean but runtime behavior does not
  • Introducing concurrency concepts without turning them into raw API memorization
Trade-Offs

Trade-offs and when to be careful

  • This comparison clarifies intent, but real systems still blend structural and concurrency patterns together.
  • The danger is using the right vocabulary without changing the underlying execution design.
Common Mistakes

Frequent mistakes to watch for

  • Assuming SOLID and GoF patterns automatically make code concurrency-safe
  • Treating asynchronous execution as a drop-in wrapper instead of a design boundary
  • Ignoring pool sizing and queue behavior because the object structure looks clean
  • Believing message passing automatically removes all consistency problems
Related Pages

Related concepts


What To Read Next