Master Java Concurrency: Threads, Thread Pools, and Synchronization
This article provides a comprehensive overview of Java concurrency, covering thread creation methods, thread pools, thread models, the Future and Fork/Join frameworks, volatile and CAS mechanisms, AQS, synchronized locks, and various concurrent queue implementations, with practical code examples and references for deeper study.
Introduction
This article summarizes Java concurrency from a high‑level perspective, aiming to give readers a quick understanding of what to watch for when practicing concurrent programming in Java, including thread safety, tool selection, and core JVM concepts.
Java Threads
High‑concurrency in Java is built on multithreading. The article first explains how to create a thread and let it perform work.
Extending Thread Class
Subclass Thread and override run(). Example:
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(); }
}
}Implementing Runnable Interface
Implement Runnable and pass an instance to a Thread constructor. Example:
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(); }
}
}Using FutureTask
Wrap a Callable in a FutureTask to start a thread and monitor its completion.
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
Beyond creating threads, a thread model guides code organization, resource sharing, and communication. The article mentions Netty’s Reactor model (single‑thread per channel) as a good example.
Java ThreadPool
Thread pools avoid the cost of repeatedly creating threads. The article shows how to obtain a pool, submit tasks, and shut it down.
int cpuCoreCount = Runtime.getRuntime().availableProcessors();
ThreadFactory threadFactory = new AThreadFactory();
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(cpuCoreCount, threadFactory);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(threadFactory);
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(cpuCoreCount, threadFactory);
fixedThreadPool.submit(runnable);
cachedThreadPool.submit(runnable);
scheduled.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
// shutdown after use
fixedThreadPool.shutdownNow();
cachedThreadPool.shutdownNow();
scheduled.shutdownNow();ThreadPoolExecutor and ScheduledThreadPoolExecutor
These are the core classes for general and scheduled pools. The article links to detailed analyses.
Common Pool Types
newFixedThreadPool – fixed number of threads.
newCachedThreadPool – creates threads on demand and reuses idle ones.
newScheduledThreadPool – supports periodic and delayed tasks.
Future
The Future interface represents a result that will be available later, allowing cancellation, status checks, and result retrieval.
Fork/Join Framework
Divides large tasks into smaller subtasks that can be processed in parallel, using a work‑stealing algorithm. Example shows a merge‑sort implementation.
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 forkJoinCase, normalCase, mockArray omitted for brevity)
}
class MergeSortTask extends RecursiveAction {
private static final int THRESHOLD = 100000;
private final MergeSortWorker worker = new MergeSortWorker();
private int[] data; private int left; private int right;
public MergeSortTask(int[] arr, int l, int r) { data = arr; left = l; right = r; }
@Override protected void compute() {
if (right - left < THRESHOLD) worker.sort(data, left, right);
else {
int mid = left + (right - left) / 2;
invokeAll(new MergeSortTask(data, left, mid), new MergeSortTask(data, mid + 1, right));
worker.merge(data, left, mid, right);
}
}
}
class MergeSortWorker {
void merge(int[] arr, int l, int m, int r) { /* merge logic */ }
void sort(int[] arr, int l, int r) { /* recursive sort */ }
}volatile Keyword
Ensures visibility of shared variables across threads by forcing writes to be flushed to main memory and reads to fetch the latest value.
Atomic Operations (CAS)
Compare‑and‑swap provides lock‑free atomic updates. The article shows how to obtain Unsafe via reflection and discusses its use in concurrent structures like ConcurrentHashMap.
class UnsafeHolder {
private static Unsafe U = null;
public static Unsafe getUnsafe() {
if (U == null) {
synchronized (UnsafeHolder.class) {
if (U == null) {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
U = (Unsafe) f.get(null);
} catch (Exception e) { e.printStackTrace(); }
}
}
}
return U;
}
}AbstractQueuedSynchronizer (AQS)
AQS underpins Java’s lock implementations, supporting exclusive and shared modes, fair and non‑fair policies.
synchronized Lock
Provides a heavier‑weight monitor lock; every object can be used as a lock. The article outlines instance, static, and block synchronization.
Concurrent Queues
Java offers various blocking and non‑blocking queue implementations (e.g., LinkedBlockingQueue, SynchronousQueue, DelayQueue, PriorityBlockingQueue) to safely exchange data between producer and consumer threads.
Conclusion
The article summarizes core Java concurrency techniques, points to deeper resources, and encourages further exploration of JVM internals, operating‑system interactions, and hardware fundamentals to master high‑performance concurrent applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
