Java • Java-Specific Topics

Threads vs. Processes — Explain threads vs processes at a high level (conceptual)

Understanding how your computer runs multiple tasks at once using processes and threads.

Java programming emblem with a coffee cup, code braces, and terminal
Inside this lesson 10 sections 5 questions 5 figures

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

Early operating systems like Multics introduced time-sharing, allowing multiple users to share a single computer by rapidly switching between their programs. Each user's program ran as a separate process.

1970s • Unix and Process Model

The Unix operating system popularized the process model, giving each running program its own isolated memory space. This became the foundation for modern operating systems.

1980s–90s • Threads Emerge

Researchers realized that creating full processes was expensive. Threads (sometimes called lightweight processes) were introduced so that a single process could handle multiple tasks internally without the overhead of creating entirely new processes.

1995 • Java Launches with Built-In Threads

Java was one of the first mainstream languages to include built-in threading support as part of the language itself, with the Thread class and Runnable interface available from day one.

2000s–Present • Multi-Core Revolution

Modern CPUs have multiple cores, making threads even more important. Java continues to evolve its threading model with features like the Executor framework, CompletableFuture, and virtual threads.

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.

1

Process Isolation

Each process has its own separate memory space. One process cannot directly read or write another process's memory. This provides safety — a bug in one program won't corrupt another.
2

Shared Memory in Threads

Threads within the same process share the same memory. This makes communication between threads fast and easy, but it also creates the risk of data conflicts when two threads change the same variable.
3

Lightweight vs. Heavyweight

Creating a new process is heavyweight — the OS must allocate fresh memory and resources. Creating a thread is lightweight because it reuses the process's existing memory.
4

Concurrency

Concurrency means making progress on multiple tasks during overlapping time periods. Both processes and threads enable concurrency, but threads do it more efficiently within a single application.
✦

KEY TAKEAWAY

Think of a process like a separate restaurant — each restaurant has its own kitchen, staff, and ingredients. A thread is like a chef working in that kitchen. Multiple chefs (threads) share the same kitchen supplies (memory), so they can work on different dishes simultaneously. But they need to coordinate so they don't grab the same pan at the same time!

SECTION 3

Visual Explanation — Process vs. Thread Architecture

Processes vs. Threads — Memory ArchitecturePROCESS AOwn Memory Space (Heap, Static Data)Address: 0x00A0 – 0x0FFFThread 1Own StackOwn RegistersProgram CounterThread 2Own StackOwn RegistersProgram CounterShared: Heap Memory, Code, Open FilesOS-Assigned Resources:PID, File Descriptors, Network SocketsPROCESS BOwn Memory Space (Heap, Static Data)Address: 0x1000 – 0x1FFFThread 1 (main)Own StackOwn RegistersProgram CounterShared: Heap Memory, Code, Open FilesOS-Assigned Resources:PID, File Descriptors, Network Sockets✕Processes are isolated (✕ = no direct memory access between them)
This diagram shows two separate processes (A and B), each with their own memory space. Process A has two threads that share the same heap memory and code, while Process B runs independently. The red ✕ between them indicates that one process cannot directly access the other's memory.

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

Every Java application runs as a single process on your operating system, but that process can contain many threads. When you write 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

Thread Lifecycle in a Java ProcessJVM Process (single OS process)NEWstart()RUNNABLEscheduledRUNNINGrun() endsTERMINATEDBLOCKEDwait/sleepnotifyWhat Each Thread Owns vs. SharesPrivate to Each ThreadStack · Registers · Program CounterShared Among All ThreadsHeap · Code · Static Variables · FilesA Java Thread moves through these states within a single JVM process
This diagram shows the lifecycle of a Java thread within a JVM process. A thread starts in the NEW state, becomes RUNNABLE after 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.
FeatureProcessThread
MemorySeparate address space for each processShares address space with other threads in the same process
Creation CostHeavyweight — OS allocates new memory, file descriptors, etc.Lightweight — only needs a new stack and register set
CommunicationRequires IPC (pipes, sockets, shared files) — slowDirect access to shared variables — fast but risky
Crash ImpactOne process crash does not affect othersOne thread crash can bring down the entire process
Context SwitchSlower — must swap out entire memory mapFaster — memory map stays the same
Java SupportUse ProcessBuilder or Runtime.exec() to start new processesUse 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. 1

    Step 1 — Define the Task Using Runnable

    First, we define what each thread should do by creating a class that implements the Runnable interface. The run() 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. 2

    Step 2 — Create Thread Objects

    Next, we create two Thread objects, passing our Runnable task 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. 3

    Step 3 — Start the Threads

    We call start() (not run()) on each thread. Calling start() tells the JVM to create a new thread of execution and then call run() on that new thread. If you accidentally called run() directly, it would execute on the current thread — no new thread would be created.
    t1.start(); t2.start();
  4. 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. 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.

AspectProcesses — StrengthsThreads — Strengths
SafetyComplete isolation prevents one program from corrupting another's data.Shared data makes collaboration easy, but programmers must prevent data races.
PerformanceHigher overhead for creation and switching — suitable for long-running, independent tasks.Low overhead for creation and switching — ideal for many small, related tasks.
CommunicationRequires inter-process communication (IPC) mechanisms — more complex but safer.Threads read and write shared variables directly — simpler but needs synchronization.
ScalabilityCan 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

Use processes when you need bulletproof isolation — like running separate applications on your phone. Use threads when parts of the same application need to work together efficiently — like a video game rendering graphics, processing input, and playing sound all at once. In Java, most of your multitasking within a single program will involve threads.
⚠

Common Pitfall

The biggest risk with threads is a race condition — when two threads read and write the same variable at the same time, leading to unpredictable results. Imagine two cashiers both trying to update the same bank balance at the same time. Java provides the 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.

ConceptWhat You Learned TodayAdvanced Version
Creating ThreadsManually create Thread objects and call start()Use ExecutorService and thread pools that reuse threads for efficiency
SynchronizationUnderstand that shared memory can cause conflictsUse locks, semaphores, atomic variables, and concurrent collections
CommunicationThreads share heap memory; processes use IPCCompletableFuture for asynchronous programming; message queues for distributed systems
Thread TypesPlatform threads mapped 1:1 to OS threadsVirtual 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

Explain in your own words why two threads in the same process can share data easily, but two separate processes cannot. What makes their memory situations different?
Show answer
Threads within the same process share the same address space, meaning they can read and write the same heap memory directly. Each thread sees the same objects and variables in the heap. In contrast, each process has its own separate memory space, completely isolated from other processes. The operating system enforces this isolation for security and stability. If Process A tries to access Process B's memory, the OS will block it. For processes to share data, they must use inter-process communication (IPC) mechanisms like pipes or sockets, which are slower than direct memory access.

Question 2: BASIC CALCULATION

A Java program creates 4 threads using 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
The program runs in exactly 1 process — the JVM process. Inside that process, there are 5 threads total: the main thread (which Java creates automatically when your program starts) plus the 4 threads you created explicitly. All 5 threads share the same heap memory within that single process. Each thread has its own private stack for local variables, but they can all access the same objects on the heap. This is a key advantage of threads: you get concurrent execution without the overhead of multiple processes.

Question 3: INTERMEDIATE

Consider the following scenario: Thread A reads a shared variable 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
This is a classic race condition. If both threads read the counter at the same time, they both see 10. Thread A writes 11, and Thread B also writes 11. The counter should be 12 (10 + 1 + 1), but it ends up as 11 — one increment is lost. This problem exists because threads share heap memory, so both threads access the same 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

You're building a music player app in Java. It needs to: (1) play audio, (2) display the waveform animation, and (3) listen for user button clicks. Should you use multiple processes or multiple threads for these tasks? Justify your answer with at least two reasons.
Show answer
You should use multiple threads within a single process for several reasons. First, all three tasks need to share data — for example, the audio playback position must be known by the waveform display to animate correctly, and the button listener needs to control the audio player. Threads share heap memory, making this communication simple and fast. Using separate processes would require complex IPC to share this data. Second, threads are lightweight to create and have low context-switching overhead, which is important for a responsive music player that needs to update the display smoothly while playing audio. Third, if one feature crashes in a separate process, the others keep running — but in a music player, if the audio engine crashes, there's no point showing the waveform, so process isolation doesn't provide meaningful benefit here.

Question 5: CRITICAL THINKING

Web browsers like Chrome use a separate process for each tab, while many Java web servers use a separate thread for each client request. Analyze why each application chose a different approach. What are the trade-offs of each decision?
Show answer
Chrome uses separate processes per tab primarily for isolation and security. If one tab crashes (due to a buggy website or malicious code), the other tabs continue running unaffected. Since browser tabs are largely independent — they don't need to share much data — the overhead of separate processes is acceptable. Security is critical because web content from different sites should not be able to access each other's data. A Java web server, on the other hand, uses threads per request because the requests often need access to shared resources like a database connection pool, cached data, and application state. Threads make this sharing natural and fast. The server handles thousands of requests per second, so the lightweight nature of threads (fast creation, low memory overhead, quick context switching) is essential for performance. The trade-off is that a bug in one request handler could theoretically crash the entire server process, but careful programming and thread safety practices mitigate this risk.

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.

Varsity Tutors • Java • Threads vs. Processes