Overview
Concurrency is a fundamental concept in modern software development, enabling programs to execute multiple tasks simultaneously for improved efficiency, responsiveness, and scalability. Java provides a rich set of APIs and language features for building concurrent applications.
What is Concurrency?
Section titled “What is Concurrency?”Concurrency is the ability of a program to execute multiple tasks (threads) seemingly at the same time. In Java, concurrency is achieved by running multiple threads within a single process.
- Parallelism: Actual simultaneous execution on multiple processors/cores.
- Concurrency: Structuring a program so tasks can be interleaved or run in parallel.
Benefits:
- Improved resource utilization
- Better application responsiveness
- Scalability on multi-core systems
Processes vs Threads
Section titled “Processes vs Threads”- Process: An independent executing program with its own memory space.
- Thread: A lightweight unit of execution within a process. Threads share the same memory space but have their own call stacks and program counters.
| Aspect | Process | Thread |
|---|---|---|
| Memory | Separate | Shared (within process) |
| Overhead | High | Low |
| Communication | IPC (slow) | Shared variables (fast) |
| Failure | Isolated | May affect others |
Java Memory Model Basics
Section titled “Java Memory Model Basics”The Java Memory Model (JMM) defines how threads interact through memory and what behaviors are allowed in concurrent execution.
- Main memory: Shared by all threads
- Working memory: Each thread has its own working memory (cache)
- Visibility: Changes made by one thread may not be immediately visible to others unless properly synchronized
- Happens-before relationship: Guarantees visibility and ordering of actions (e.g., via
synchronized,volatile, thread start/join)
Thread Lifecycle
Section titled “Thread Lifecycle”A Java thread goes through several states:
- New: Thread is created but not yet started
- Runnable: Thread is eligible to run (waiting for CPU)
- Running: Thread is executing
- Blocked/Waiting: Thread is waiting for a monitor lock or another thread’s action
- Timed Waiting: Waiting for a specified period
- Terminated: Thread has completed execution or was stopped

Thread Creation
Section titled “Thread Creation”1. Implementing Runnable
Section titled “1. Implementing Runnable”class MyRunnable implements Runnable { public void run() { System.out.println("Hello from Runnable!"); }}
Thread t = new Thread(new MyRunnable());t.start();2. Extending Thread
Section titled “2. Extending Thread”class MyThread extends Thread { public void run() { System.out.println("Hello from Thread!"); }}
Thread t = new MyThread();t.start();3. Using Callable and Future
Section titled “3. Using Callable and Future”import java.util.concurrent.*;
Callable<Integer> task = () -> { Thread.sleep(1000); return 42;};ExecutorService executor = Executors.newSingleThreadExecutor();Future<Integer> future = executor.submit(task);System.out.println(future.get()); // blocks until result is availableexecutor.shutdown();4. Using Executors
Section titled “4. Using Executors”ExecutorService executor = Executors.newFixedThreadPool(2);executor.submit(() -> System.out.println("Task 1"));executor.submit(() -> System.out.println("Task 2"));executor.shutdown();Code Examples
Section titled “Code Examples”Creating Multiple Threads
Section titled “Creating Multiple Threads”for (int i = 0; i < 5; i++) { Thread t = new Thread(() -> { System.out.println(Thread.currentThread().getName()); }); t.start();}Lambda Expressions (Java 8+)
Section titled “Lambda Expressions (Java 8+)”Runnable task = () -> System.out.println("Running in a thread");new Thread(task).start();Thread Naming
Section titled “Thread Naming”Thread t = new Thread(() -> {}, "Worker-1");t.start();System.out.println(t.getName()); // Worker-1Best Practices
Section titled “Best Practices”- Prefer higher-level concurrency utilities (
Executors,Concurrentcollections) over manual thread management - Minimize shared mutable state
- Always properly synchronize access to shared variables
- Use
volatilefor variables accessed by multiple threads without locking (when appropriate) - Always shut down executors to free resources
- Catch and handle exceptions in threads to avoid silent failures
- Name threads for easier debugging