SECTION 1
Historical Context & Motivation
In the early days of computing, machines could only run one program at a time. If you wanted to print a document, the entire computer froze until the printer finished. As computers grew more powerful and users demanded more flexibility, operating system designers developed the concept of multitasking — the ability to run multiple programs seemingly at the same time. This led to two key ideas: processes and threads.
1960s • Time-Sharing Operating Systems
1970s • Unix and Process Model
1980s–90s • Threads Emerge
1995 • Java Launches with Built-In Threads
2000s–Present • Multi-Core Revolution
The core question this lesson addresses is: What is the difference between a process and a thread, and why does Java give you direct control over threads? Understanding this distinction is essential for writing programs that can do multiple things at once — like downloading a file while updating a progress bar.
SECTION 2
Core Principles & Definitions
Before diving into code, you need to understand the fundamental concepts. A process is a running instance of a program. When you open a web browser, the operating system creates a process for it. That process gets its own chunk of memory, its own resources, and is isolated from other processes. If your browser crashes, your music player keeps running because they are separate processes.
A thread is a smaller unit of execution that lives inside a process. A single process can contain multiple threads, and all those threads share the same memory space. Think of a process as a house, and threads as the people living in that house — they all share the kitchen, living room, and bathroom, but each person can be doing a different task at the same time.
Process Isolation
Shared Memory in Threads
Lightweight vs. Heavyweight
Concurrency
KEY TAKEAWAY
SECTION 3
Visual Explanation — Process vs. Thread Architecture
The diagram above is the single most important visual for understanding this concept. Notice that within Process A, both Thread 1 and Thread 2 have their own stack, registers, and program counter — these are the private parts of each thread. However, they share the heap memory, the program's compiled code, and any open files. This shared access is what makes threads fast at communicating but also risky when not properly coordinated.
Between Process A and Process B, there is complete isolation. Process B cannot peek into Process A's memory, and vice versa. If they need to communicate, they must use special mechanisms provided by the operating system, such as inter-process communication (IPC) — pipes, sockets, or shared files. This is slower but safer than thread-to-thread communication within the same process.
SECTION 4
How Threads and Processes Work Under the Hood
What the Operating System Does
When you run a Java program, the operating system creates a new process for the Java Virtual Machine (JVM). Inside that process, the JVM starts with one thread called the main thread — this is the thread that executes your public static void main(String[] args) method. From there, your code can create additional threads using Java's Thread class.
Context Switching
Most computers have a limited number of CPU cores (typically 4 to 16). But you might have dozens of processes and hundreds of threads running. The operating system uses a technique called context switching to rapidly alternate between threads, giving each one a tiny slice of CPU time. Switching between threads in the same process is faster than switching between different processes because threads share memory — the CPU doesn't need to reload an entirely new memory map.
The Java Memory Model
In Java, the JVM manages memory in two major regions. The heap is shared among all threads — this is where objects created with new are stored. The stack is private to each thread — it holds local variables, method parameters, and return addresses. This means if two threads both access the same object on the heap, they could conflict, which is why Java provides tools like the synchronized keyword to prevent problems.
Important Distinction
new Thread() in Java, you are creating a new thread inside the existing JVM process — not a new process.SECTION 5
Side-by-Side Comparison — Processes vs. Threads
start() is called, and can move to BLOCKED if it waits for a resource. The bottom section clarifies what data is private to each thread and what is shared.| Feature | Process | Thread |
|---|---|---|
| Memory | Separate address space for each process | Shares address space with other threads in the same process |
| Creation Cost | Heavyweight — OS allocates new memory, file descriptors, etc. | Lightweight — only needs a new stack and register set |
| Communication | Requires IPC (pipes, sockets, shared files) — slow | Direct access to shared variables — fast but risky |
| Crash Impact | One process crash does not affect others | One thread crash can bring down the entire process |
| Context Switch | Slower — must swap out entire memory map | Faster — memory map stays the same |
| Java Support | Use ProcessBuilder or Runtime.exec() to start new processes | Use Thread class or Runnable interface directly |
Key differences between processes and threads
SECTION 6
Worked Example — Creating Threads in Java
Let's walk through a practical example of creating and running threads in Java. Imagine you're building a simple program that downloads two files simultaneously. Instead of waiting for the first download to finish before starting the second, you can use threads to handle both at the same time.
Creating Two Threads to Simulate Concurrent Downloads
- 1
Step 1 — Define the Task Using Runnable
First, we define what each thread should do by creating a class that implements theRunnableinterface. Therun()method contains the code the thread will execute. Here's a simplified version:class DownloadTask implements Runnable { String fileName; DownloadTask(String name) { this.fileName = name; } public void run() { System.out.println("Downloading " + fileName + " on " + Thread.currentThread().getName()); } } - 2
Step 2 — Create Thread Objects
Next, we create twoThreadobjects, passing ourRunnabletask to each one. Each Thread wraps around a Runnable and is ready to execute it.Thread t1 = new Thread(new DownloadTask("image.png")); Thread t2 = new Thread(new DownloadTask("video.mp4")); - 3
Step 3 — Start the Threads
We callstart()(notrun()) on each thread. Callingstart()tells the JVM to create a new thread of execution and then callrun()on that new thread. If you accidentally calledrun()directly, it would execute on the current thread — no new thread would be created.t1.start(); t2.start(); - 4
Step 4 — Observe Concurrent Execution
When the program runs, both threads execute at the same time. The output might be:Downloading image.png on Thread-0 Downloading video.mp4 on Thread-1— Note: the order might vary on each run because threads are scheduled by the OS. - 5
Step 5 — Understand What Happened at the OS Level
Your program is one process (the JVM). Inside that single process, there are now three threads: the main thread, Thread-0, and Thread-1. They all share the same heap memory, which means they can access the same objects. Each thread has its own call stack where its local variables live.1 process, 3 threads (main + 2 download threads), all sharing the JVM's heap memory.
SECTION 7
Strengths and Limitations
Neither processes nor threads are universally better — each has strengths that make it the right choice in different situations. Understanding when to use each is a crucial skill for any Java developer.
| Aspect | Processes — Strengths | Threads — Strengths |
|---|---|---|
| Safety | Complete isolation prevents one program from corrupting another's data. | Shared data makes collaboration easy, but programmers must prevent data races. |
| Performance | Higher overhead for creation and switching — suitable for long-running, independent tasks. | Low overhead for creation and switching — ideal for many small, related tasks. |
| Communication | Requires inter-process communication (IPC) mechanisms — more complex but safer. | Threads read and write shared variables directly — simpler but needs synchronization. |
| Scalability | Can run on different machines in distributed systems. | Limited to one machine, but many threads can run within one process. |
When to choose processes vs. threads
KEY TAKEAWAY
Common Pitfall
synchronized keyword and lock objects to prevent this.SECTION 8
Connection to Advanced Concurrency
The basic Thread class you've learned about is just the starting point. As Java programs grow in complexity, managing dozens or hundreds of threads manually becomes impractical. Java provides higher-level tools that build on the thread-vs-process foundation.
| Concept | What You Learned Today | Advanced Version |
|---|---|---|
| Creating Threads | Manually create Thread objects and call start() | Use ExecutorService and thread pools that reuse threads for efficiency |
| Synchronization | Understand that shared memory can cause conflicts | Use locks, semaphores, atomic variables, and concurrent collections |
| Communication | Threads share heap memory; processes use IPC | CompletableFuture for asynchronous programming; message queues for distributed systems |
| Thread Types | Platform threads mapped 1:1 to OS threads | Virtual threads (Java 21+) — extremely lightweight, thousands can run simultaneously |
From basics to advanced concurrency in Java
One of the most exciting recent additions to Java is virtual threads, introduced in Java 21. Virtual threads are managed by the JVM rather than the operating system, making them incredibly lightweight. You could create a million virtual threads in a single JVM process, something impossible with traditional platform threads. This doesn't change the process-vs-thread distinction — virtual threads still live inside a single process and share heap memory — but it dramatically lowers the cost of using threads.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Show answer
Question 2: BASIC CALCULATION
new Thread() and starts them all. Including the main thread, how many threads are running in the JVM process? How many processes does this program use?Show answer
Question 3: INTERMEDIATE
counter (which equals 10), adds 1, and writes 11 back. Thread B does the same thing at the same time. What could go wrong, and would this problem exist if A and B were separate processes instead of threads?Show answer
counter variable directly. If A and B were separate processes, they would each have their own copy of counter in separate memory spaces. They could not accidentally interfere with each other's data. However, they also could not easily collaborate. In Java, you would fix this thread issue using the synchronized keyword to ensure only one thread modifies the counter at a time.Question 4: APPLIED
Show answer
Question 5: CRITICAL THINKING
Show answer
SUMMARY
Lesson Summary
Summary
A process is an independent running program with its own isolated memory space, managed by the operating system. A thread is a lighter unit of execution that lives inside a process and shares memory with other threads in the same process. Threads are cheaper to create and faster to switch between, but the trade-off is that shared memory introduces risks like race conditions, which require careful synchronization.
In Java, every application runs as a single JVM process that starts with a main thread. You create additional threads using the Thread class or the Runnable interface. Each thread gets its own stack but shares the heap with all other threads. Use threads when tasks within one program need to run concurrently and share data; use separate processes when you need complete isolation between programs.