A Comprehensive Overview of Java Concurrency Programming

This article provides a high‑level summary of Java concurrency, covering thread creation methods, thread models, thread pools, Future and CompletableFuture, the Fork/Join framework, volatile, CAS, AQS, synchronized locks, and concurrent queue implementations, with code examples and reference links for deeper study.

Architecture Digest
Architecture Digest
Architecture Digest
A Comprehensive Overview of Java Concurrency Programming

The article aims to give readers a broad yet concise overview of Java concurrency, explaining what to watch for when writing concurrent code, how to ensure thread safety, and which tools to choose for different scenarios.

Java Thread Creation

Three basic ways to start a new thread are demonstrated: extending Thread and overriding run(), implementing Runnable and passing it to a Thread, and using FutureTask which implements both Runnable and Future.

/**
 * Created by hujian06 on 2017/10/31.
 * the demo of thread
 */
public class ThreadDemo {
    public static void main(String ... args) {
        AThread aThread = new AThread();
        aThread.start();
    }
}

class AThread extends Thread {
    @Override
    public void run() {
        System.out.println("Current Thread Name:" + Thread.currentThread().getName());
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
    }
}
/**
 * Created by hujian06 on 2017/10/31.
 * the demo of Runnable
 */
public class ARunnableDemo {
    public static void main(String ... args) {
        ARunnable aRunnable = new ARunnable();
        Thread thread = new Thread(aRunnable);
        thread.start();
    }
}

class ARunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Current Thread Name:" + Thread.currentThread().getName());
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
    }
}
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 * Created by hujian06 on 2017/10/31.
 * the demo of FutureTask
 */
public class FutureTaskDemo {
    public static void main(String ... args) {
        ACallable callAble = new ACallable();
        FutureTask<String> futureTask = new FutureTask<>(callAble);
        Thread thread = new Thread(futureTask);
        thread.start();
        while (!futureTask.isDone()) {}
        try {
            String result = futureTask.get();
            System.out.println("Result:" + result);
        } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
    }
}

class ACallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "Thread-Name:" + Thread.currentThread().getName();
    }
}

Thread Model

The article discusses simple thread models and introduces Netty's Reactor‑based thread model, illustrating how assigning a single NioEventLoop per channel avoids synchronization overhead.

Java Thread Pools

Thread pools reduce the cost of repeatedly creating threads. The article shows how to create fixed, cached, scheduled, and single‑thread executors, and explains the internal workings of ThreadPoolExecutor and ScheduledThreadPoolExecutor.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Created by hujian06 on 2017/10/31.
 * the demo of Executors
 */
public class ExecutorsDemo {
    public static void main(String ... args) {
        int cpuCoreCount = Runtime.getRuntime().availableProcessors();
        AThreadFactory threadFactory = new AThreadFactory();
        ARunnable runnAble = new ARunnable();
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(cpuCoreCount, threadFactory);
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool(threadFactory);
        ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(cpuCoreCount, threadFactory);
        ScheduledExecutorService singleThreadExecutor = Executors.newSingleThreadScheduledExecutor(threadFactory);
        fixedThreadPool.submit(runnAble);
        cachedThreadPool.submit(runnAble);
        newScheduledThreadPool.scheduleAtFixedRate(runnAble, 0, 1, TimeUnit.SECONDS);
        singleThreadExecutor.scheduleWithFixedDelay(runnAble, 0, 100, TimeUnit.MILLISECONDS);
        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
        fixedThreadPool.shutdownNow();
        cachedThreadPool.shutdownNow();
        newScheduledThreadPool.shutdownNow();
        singleThreadExecutor.shutdownNow();
    }
}

class AThreadFactory implements ThreadFactory {
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    @Override
    public Thread newThread(Runnable r) {
        return new Thread("aThread-" + threadNumber.incrementAndGet());
    }
}

Future and CompletableFuture

Future represents a placeholder for a result that will become available later; CompletableFuture (Java 8) extends this with rich composition capabilities.

Fork/Join Framework

The Fork/Join framework splits large tasks into smaller subtasks that are processed in parallel, using a work‑stealing algorithm. An example of a merge‑sort implementation is provided.

import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/**
 * Created by hujian06 on 2017/10/23.
 * merge sort by fork/join
 */
public class ForkJoinMergeSortDemo {
    public static void main(String ... args) {
        new Worker().runWork();
    }
}

class Worker {
    private static final boolean isDebug = false;
    public void runWork() {
        int[] array = mockArray(200000000, 1000000);
        forkJoinCase(array);
        normalCase(array);
    }
    // ... (methods omitted for brevity) ...
}

class MergeSortTask extends RecursiveAction {
    private static final int threshold = 100000;
    private final MergeSortWorker mergeSortWorker = new MergeSortWorker();
    private int[] data; private int left; private int right;
    public MergeSortTask(int[] array, int l, int r) { this.data = array; this.left = l; this.right = r; }
    @Override
    protected void compute() {
        if (right - left < threshold) {
            mergeSortWorker.sort(data, left, right);
        } else {
            int mid = left + (right - left) / 2;
            invokeAll(new MergeSortTask(data, left, mid), new MergeSortTask(data, mid + 1, right));
            mergeSortWorker.merge(data, left, mid, right);
        }
    }
}
// Additional worker classes omitted for brevity

volatile Keyword

volatile guarantees visibility of writes to shared variables across threads by inserting a lock‑prefix instruction that forces a cache line to be written back to main memory.

CAS (Compare‑And‑Swap)

CAS provides lock‑free atomic updates; it is heavily used in classes like ConcurrentHashMap and the AtomicXXX family. The article also shows how to obtain an Unsafe instance via reflection.

class UnsafeHolder {
    private static Unsafe U = null;
    public static Unsafe getUnsafe() {
        if (U == null) {
            synchronized (UnsafeHolder.class) {
                if (U == null) {
                    try {
                        Field field = Unsafe.class.getDeclaredField("theUnsafe");
                        field.setAccessible(true);
                        U = (Unsafe) field.get(null);
                    } catch (Exception e) { e.printStackTrace(); }
                }
            }
        }
        return U;
    }
}

AQS (AbstractQueuedSynchronizer)

AQS underlies Java’s lock implementations, supporting exclusive and shared modes, which are used to build ReentrantLock, Semaphore, CountDownLatch, etc.

synchronized

All objects can serve as monitors; synchronized blocks acquire the monitor before entering and release it on exit, with the JVM generating monitorenter and monitorexit bytecode.

Concurrent Queues

The article classifies Java’s concurrent queues (blocking, delay, priority, etc.) and explains their semantics such as throwing exceptions, returning special values, blocking, or timing out.

Conclusion

The article summarizes core Java concurrency techniques, points to deeper resources, and encourages readers to first master the high‑level APIs before diving into JVM internals, OS memory management, and CPU architecture.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyThreadPoolThreadCASAQSFuture
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

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.