Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 40 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Java Concurrency Patterns and Features

Concurrency Patterns and features found in Java, through multithreaded programming.
Concurrency Patterns and features found in Java, through multithreaded programming.
This repository covers **Java 8 through Java 17** (with documentation stubs for Java 21 Project Loom APIs).

## Features:
* [Threads and Runnables](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/threads/UsingThreads.java)
Expand All @@ -15,46 +16,69 @@ Concurrency Patterns and features found in Java, through multithreaded programmi
* [Barriers](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/synchronizers/UsingBarriers.java)
* [Synchronized Collections](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingSynchronizedCollections.java)
* [Concurrent Collections](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java)
* [CopyOnWriteArrayList](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java#L89)
* [ConcurrentHashMap](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java#L40)
* [Blocking Queue](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java#L141)
* [CopyOnWriteArrayList](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java)
* [ConcurrentHashMap](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java) — now includes Java 8 bulk ops: `merge`, `compute`, `forEach`, `reduceValues`, `search`
* [Blocking Queue](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/collections/UsingConcurrentCollections.java)
* [Executors](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Fixed Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L94)
* [Cached Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L65)
* [Single Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L51)
* [Scheduled Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L122)
* [Single Thread Scheduled Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L139)
* [Work-Stealing Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java#L156)
* [Atomics](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/atomics/UsingAtomics.java)
* [Fixed Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Cached Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Single Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Scheduled Thread Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Single Thread Scheduled Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* [Work-Stealing Pool](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/executors/UsingExecutors.java)
* Virtual Thread-Per-Task Executor *(Java 21 — see [`UsingVirtualThreads`](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/threads/UsingVirtualThreads.java))*
* [Atomics](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/atomics/UsingAtomics.java) — now includes **VarHandle** (Java 9)
* [Futures](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/features/futures)
* [FutureTask](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/futures/UsingFutureTasks.java)
* [CompletableFuture](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/futures/UsingCompletableFuture.java)
* [CompletableFuture](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/futures/UsingCompletableFuture.java) — now includes `orTimeout` / `completeOnTimeout` (Java 9)
* [Structured Concurrency](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/futures/UsingStructuredConcurrency.java) *(Java 21 — doc stub)*
* [Fork/Join Framework](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/forkjoin/UsingForkJoinFramework.java)
* [Parallel Streams](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/parallel_stream/UsingParallelStreams.java)
* [Parallel Streams](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/parallel_stream/UsingParallelStreams.java) — updated to use `Stream.toList()` (Java 16)
* [Java Memory Model](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/java_memory_model/WhatIsJavaMemoryModel.java)
* [Reactive Streams — `java.util.concurrent.Flow`](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/java_memory_model/UsingReactiveStreams.java) *(Java 9 — Publisher, Subscriber, Processor, back-pressure)*
* [Virtual Threads](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/threads/UsingVirtualThreads.java) *(Java 21 — doc stub)*
* [Scoped Values](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/features/threads/UsingScopedValues.java) *(Java 21 — doc stub)*

## Patterns
* [Protect Shared State](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/shared_state)
* [Atomic Compound Actions](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/compound_actions)
* [Lock Split](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/lock_split)
* [Fixed Lock Ordering](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/fixed_lock_ordering)
* [Thread Local Confinement](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/thread_confinement)
* [Immutable Object](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/immutable_object)
* [Thread Local Confinement](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/thread_confinement) — `ThreadLocal.withInitial()` (Java 8); `DateTimeFormatter` replaces `SimpleDateFormat` (Java 8)
* [Immutable Object](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/thread_safe/immutable_object) — inner value classes converted to **records** (Java 16); switch expression (Java 14)
* [Safe Lazy Initialization](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/thread_safe/initialization/SafeInitializationHolder.java)
* [Safe Publishing](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/thread_safe/publishing/SafePublishing.java)
* [Resource Pool](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/resource_pool)
* [Condition Queues](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/condition_queues)
* [wait-notify](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/condition_queues/WaitNotifyQueue.java)
* [await-signal](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/condition_queues/ExplicitConditionQueue.java)
* [Background Task Executor](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/task_execution/BackgroundTaskExecutor.java)
* [Structured Background Task Executor](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/task_execution/StructuredBackgroundTaskExecutor.java) *(Java 21 — doc stub)*
* [Task Cancel](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/task_cancel)
* [Producer-Consumer](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/producer_consumer/ProducerConsumer.java)
* [Virtual Thread Producer-Consumer](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/producer_consumer/VirtualThreadProducerConsumer.java) *(Java 21 — doc stub)*
* [Task Convergence](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/task_convergence/TaskConvergence.java)
* [Structured Task Convergence](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/task_convergence/StructuredTaskConvergence.java) *(Java 21 — doc stub)*
* [Non-Blocking with Atomics](https://github.com/LeonardoZ/java-concurrency-patterns/tree/master/src/main/java/br/com/leonardoz/patterns/non_blocking)
* [Controlled Concurrent Initialization](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/controlled_initialization/ControlledInitialization.java)
* [Parallel Divide and Conquer](https://github.com/LeonardoZ/java-concurrency-patterns/blob/master/src/main/java/br/com/leonardoz/patterns/divideconquer)

## Java Version Coverage

| Java Version | Feature Added / Updated |
|---|---|
| Java 8 | `ThreadLocal.withInitial()`, `ConcurrentHashMap` bulk ops (`merge`, `compute`, `forEach`, `reduceValues`, `search`) |
| Java 9 | `java.util.concurrent.Flow` (Reactive Streams), `CompletableFuture.orTimeout()` / `completeOnTimeout()`, `VarHandle` |
| Java 14 | Switch expressions (`EventKeeper`) |
| Java 16 | Records (`MyImmutableObject`, `Event`), `Stream.toList()` |
| Java 17 | Build target (compiler source/target) |
| Java 21 *(doc stubs — requires JDK upgrade)* | Virtual Threads, `Executors.newVirtualThreadPerTaskExecutor()`, Structured Concurrency (`StructuredTaskScope`), Scoped Values (`ScopedValue`) |

> **Java 21 stubs** are documentation-only files that describe the planned API
> with runnable code examples in Javadoc comments. They compile on Java 17
> (no executable code) and serve as a migration guide for when the project
> upgrades to JDK 21.

## About
Patterns and Algorithms inspired by the Java Concurrency in Practice book.


6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<version>3.12.1</version>
<configuration>
<!-- http://maven.apache.org/plugins/maven-compiler-plugin/ -->
<source>11</source>
<target>11</target>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
Expand Down
121 changes: 111 additions & 10 deletions src/main/java/br/com/leonardoz/features/atomics/UsingAtomics.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,56 @@
package br.com.leonardoz.features.atomics;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Atomics can be used from the java.util.concurrent.atomic.* package.
*
*
* An atomic operation is a compound action that totally completes out totally
* fails, not supporting inconsistent values or results during it's execution.
*
*
* The classes in this package supports atomic operations on single variables,
* having get and set (read and write) methods that behave like a volatile
* variable.
*
*
* The compareAndSet are commonly used in non-blocking algorithms. They
* basically tries to set a new value to a specified field, and it returns a
* boolean indicating success or not. All atomic, only blocking briefly.
*
*
* Interesting classes in this package are: AtomicBoolean, AtomicLong,
* AtomicReference<T>, AtomicMarkableReference<T> and
* AtomicReferenceFieldUpdater<T, V>.
*
* AtomicReference&lt;T&gt;, AtomicMarkableReference&lt;T&gt; and
* AtomicReferenceFieldUpdater&lt;T, V&gt;.
*
* == Java 9+: VarHandle ==
*
* {@link VarHandle} is a typed reference to a variable — an instance field, a
* static field, or an array element. It provides atomic access operations
* without the object-wrapping overhead of AtomicXxx classes, and offers finer
* control over memory ordering semantics.
*
* Key VarHandle access modes (ordered from weakest to strongest):
*
* Plain — ordinary read/write, no ordering guarantee.
* Opaque — bit-atomicity; no cross-thread ordering.
* Acquire/Release — one-sided memory ordering (like C++ acquire/release).
* Volatile — full sequential consistency (same as Java's volatile).
*
* Commonly used methods:
* get/set — plain or volatile access (depends on call site)
* getVolatile/setVolatile — volatile semantics
* getAndAdd — atomic fetch-and-add
* getAndSet — atomic fetch-and-set
* compareAndSet — CAS returning boolean
* compareAndExchange — CAS returning the witness value
* fullFence/acquireFence/releaseFence — explicit memory barriers
*
* When to prefer VarHandle over AtomicXxx:
* - You want atomic access on a plain {@code volatile} field without boxing.
* - You need fine-grained memory-order control.
* - You are building high-performance, low-allocation data structures.
*
*/
public class UsingAtomics {
Expand All @@ -45,14 +74,86 @@ public int get() {
}
}

// -------------------------------------------------------------------------
// Java 9+: same counter implemented with VarHandle
// -------------------------------------------------------------------------

/**
* A counter backed by a plain {@code volatile int} field, accessed atomically
* through a {@link VarHandle}. This avoids the extra object allocation that
* {@link AtomicInteger} requires while providing identical thread-safety
* guarantees.
*/
static class VarHandleCounter {
// The field must be accessible to the MethodHandles.lookup() at the
// call site, so it is package-private rather than private.
volatile int count = 0;

private static final VarHandle COUNT;

static {
try {
COUNT = MethodHandles.lookup()
.findVarHandle(VarHandleCounter.class, "count", int.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}

/** Atomically increment and return the new value. */
public int increment() {
// getAndAdd returns the *old* value, so we add 1 to get the new value.
return (int) COUNT.getAndAdd(this, 1) + 1;
}

/** Atomically decrement and return the new value. */
public int decrement() {
return (int) COUNT.getAndAdd(this, -1) - 1;
}

/** Volatile read of the current counter value. */
public int get() {
return (int) COUNT.getVolatile(this);
}

/**
* Compare-and-exchange: atomically sets the field to {@code newValue}
* if it currently holds {@code expected}.
*
* Unlike {@code compareAndSet}, this returns the <em>witness</em> value
* (what was actually in the field), making it useful for retry loops.
*/
public int compareAndExchange(int expected, int newValue) {
return (int) COUNT.compareAndExchange(this, expected, newValue);
}
}

public static void main(String[] args) throws InterruptedException {
var counter = new AtomicCounter();
// --- AtomicInteger counter ---
var atomicCounter = new AtomicCounter();
var cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10_000; i++) {
cachedThreadPool.execute(() -> counter.increment());
cachedThreadPool.execute(() -> atomicCounter.increment());
}
cachedThreadPool.shutdown();
cachedThreadPool.awaitTermination(4000, TimeUnit.SECONDS);
System.out.println("Result shound be 10000: Actual result is: " + counter.get());
System.out.println("AtomicInteger — expected 10000, got: " + atomicCounter.get());

// --- VarHandle counter ---
var varHandleCounter = new VarHandleCounter();
var pool2 = Executors.newCachedThreadPool();
for (int i = 0; i < 10_000; i++) {
pool2.execute(() -> varHandleCounter.increment());
}
pool2.shutdown();
pool2.awaitTermination(4000, TimeUnit.SECONDS);
System.out.println("VarHandle — expected 10000, got: " + varHandleCounter.get());

// compare-and-exchange example
var vh = new VarHandleCounter();
int witness = vh.compareAndExchange(0, 42); // should succeed: witness == 0
System.out.println("CAS witness (expected 0): " + witness + ", value is now: " + vh.get());
witness = vh.compareAndExchange(0, 99); // should fail: count is 42, not 0
System.out.println("CAS witness (expected 42): " + witness + ", value is still: " + vh.get());
}
}
Loading