Backend Development 22 min read

Understanding Java's java.util.concurrent (J.U.C) Framework and AQS Mechanism

This article provides a comprehensive overview of Java's java.util.concurrent package, detailing its core components such as atomic classes, locks, collections, executors, tools, as well as an in‑depth explanation of the AbstractQueuedSynchronizer (AQS) framework, its fields, methods, and related concurrency utilities like FutureTask, BlockingQueue, ForkJoin, and work‑stealing algorithms.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding Java's java.util.concurrent (J.U.C) Framework and AQS Mechanism

J.U.C (java.util.concurrent) Overview

J.U.C is the core Java concurrency package providing many high‑performance concurrent classes.

J.U.C, CAS, Unsafe and AQS

All classes in java.util.concurrent rely on CAS operations supplied by sun.misc.Unsafe . The AbstractQueuedSynchronizer (AQS) framework underpins locks and synchronizers, using LockSupport.unpark() and LockSupport.park() for thread blocking and waking.

J.U.C Framework

The framework consists of five parts: tools, locks, collections, executor, and atomic.

Atomic

Contains atomic variable classes that depend only on Unsafe and are used by other modules.

Locks

Provides lock classes built on Unsafe . Understanding LockSupport , then the AQS framework, then the implementation of ReentrantLock (including exclusive and shared modes) is essential.

Collections

Includes concurrent collections such as ConcurrentHashMap , CopyOnWriteArrayList , CopyOnWriteArraySet , ArrayBlockingQueue , and LinkedBlockingQueue (the latter is important for thread‑pool implementations).

Executor

Focuses on thread‑pool execution, covering Callable , Future , FutureTask , ThreadPoolExecutor , and the four implementations of RejectedExecutionHandler . It also shows how to tune ThreadPoolExecutor parameters for optimal performance.

Tools

Covers advanced utilities such as CountDownLatch , CyclicBarrier , Semaphore , Exchanger , and the Executors factory methods. These are useful for coordinating multiple threads that depend on each other's results.

AQS Details

ReentrantLock

ReentrantLock is a re‑entrant exclusive lock; its implementation relies on an inner Sync class that extends AQS.

AQS Core

AQS maintains a volatile int state and a FIFO wait queue implemented as a doubly‑linked list. The queue head holds the current owner thread.

Key Fields

private transient volatile Node head; // head of the sync queue
private transient volatile Node tail; // tail of the sync queue
private volatile int state; // synchronization state

Key Methods

protected final int getState(); // returns the current state
protected final void setState(int newState); // sets the state
protected final boolean compareAndSetState(int expect, int update); // CAS update of state

acquire(int arg)

Attempts to acquire the resource via tryAcquire . If it fails, the thread is added to the wait queue and blocks until it can acquire.

public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

addWaiter(Node mode)

Creates a new node for the current thread and tries to append it to the queue tail using CAS; if the queue is empty, it initializes a dummy head node.

private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

enq(Node node)

CAS‑spins to insert the node at the tail, initializing the queue if necessary.

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) {
            if (compareAndSetHead(new Node())) {
                tail = head;
            }
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

acquireQueued(Node node, int arg)

Loops while the node is not the head, checking if it can acquire; otherwise it may park the thread. Returns true if the thread was interrupted while waiting.

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

shouldParkAfterFailedAcquire(Node pred, Node node)

Determines whether the thread should block based on the predecessor’s wait status.

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

parkAndCheckInterrupt()

Calls LockSupport.park() and returns true if the thread was interrupted while parked.

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

Custom Synchronizer Resource Sharing

AQS supports exclusive and shared modes. Custom synchronizers need to implement methods such as isHeldExclusively() , tryAcquire(int) , tryRelease(int) , tryAcquireShared(int) , and tryReleaseShared(int) to define how the state is obtained and released.

Other J.U.C Components (to be detailed)

FutureTask

FutureTask implements RunnableFuture , allowing a Callable to be executed with a result that can be retrieved later.

public class FutureTask
implements RunnableFuture
{ ... }

BlockingQueue

The java.util.concurrent.BlockingQueue interface has several implementations, including FIFO queues ( LinkedBlockingQueue , ArrayBlockingQueue ) and priority queues ( PriorityBlockingQueue ).

Producer‑Consumer Example

public class ProducerConsumer {
    private static BlockingQueue
queue = new ArrayBlockingQueue<>(5);
    // Producer thread puts "product" into the queue
    // Consumer thread takes from the queue and processes it
    // Main method starts multiple producers and consumers
}

ForkJoin

The Fork/Join framework uses a divide‑and‑conquer approach. Tasks extend RecursiveTask and split themselves until the workload is below a threshold, then compute directly.

public class ForkJoinExample extends RecursiveTask
{
    private final int threshold = 5;
    private int first, last;
    protected Integer compute() {
        int result = 0;
        if (last - first <= threshold) {
            for (int i = first; i <= last; i++)
                result += i;
        } else {
            int middle = first + (last - first) / 2;
            ForkJoinExample left = new ForkJoinExample(first, middle);
            ForkJoinExample right = new ForkJoinExample(middle + 1, last);
            left.fork();
            right.fork();
            result = left.join() + right.join();
        }
        return result;
    }
}

Work‑Stealing Algorithm

In work‑stealing, idle threads steal tasks from other threads' deques to reduce contention. The stealing thread takes tasks from the tail, while the owning thread takes from the head. Java provides LinkedBlockingDeque and the ForkJoinPool that implements work‑stealing.

References:

https://blog.csdn.net/pange1991/article/details/80944797 https://blog.csdn.net/huzhiqiangcsdn/article/details/55251384 https://www.cnblogs.com/waterystone/p/4920797.html

Follow the public account for more interview questions and resources.

JavaConcurrencythreadpoolLocksJUCAQSForkJoinFutureTask
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.