Processes vs threads

Your programs so far did one thing at a time. Real apps don't: a banking app builds a PDF while you keep scrolling, and a server answers thousands of customers at once. They do it with threads. You'll learn what a process and a thread are, what threads share and what they don't, how the JVM starts and ends them, and the difference between running at the same time and just taking turns.

Module 12 · Multithreading⏱ 20 minIntermediate8 practice problems
1 The story

The app that froze on “Download”

Riya's college-canteen app downloads the menu, today's offers and the dish photos one after another when it opens. On slow campus Wi-Fi the screen stays blank for six seconds, and the Back button doesn't respond.

One thread: one job at a time menu offers photos 0 s6 s, screen frozen Three threads: all at once menu offers photos about 2 s screenstill responds illustrative timings on a slow network myphatshala.in
Riya

Sir, each download is only two seconds. Why does the whole app freeze?

Arjun Sir

Because one thread is doing everything: download, download, download, and only then draw the screen. While it waits for the network, nothing else can happen.

Riya

So I need more threads?

Arjun Sir

Yes. Your program is one process, and inside it you can run several threads at once. They share the same data, but each one follows its own path through the code. Let's see what that really means inside the JVM.

2 Definition

What are processes and threads?

Formal definition (write this in exams)

A process is a program in execution, with its own memory space and system resources, isolated from other processes by the operating system. A thread is the smallest unit of execution that the OS can schedule; it runs inside a process. All threads of a process share its heap memory, loaded classes and open files, but each thread has its own stack (method frames and local variables) and its own program counter. In Java, every program starts with one thread called main, and more threads are represented by java.lang.Thread objects.

In simple words

A process is a restaurant; threads are the cooks in its kitchen. They share the same fridge and stove (the heap), but each cook follows their own recipe card (their own stack).

Words you'll meet in this lesson

ProcessA running program with its own memory. Two processes can't read each other's variables.
ThreadOne path of execution inside a process. Many threads, one process.
Main threadThe thread the JVM creates to run main().
ConcurrencySeveral tasks in progress at once, possibly taking turns on one core.
ParallelismSeveral tasks running at the very same instant on different cores.
Daemon threadA background helper thread that doesn't keep the JVM alive.

Process vs thread

ProcessThread
MemoryIts own, isolatedShares the process's heap
StackEach of its threads has oneIts own stack
Cost to createHigh (new memory space)Low (a stack and some bookkeeping)
Talking to othersNeeds files, sockets, pipesJust read and write shared objects
If it crashesOther processes are safeAn uncaught error ends only that thread, but bad shared data can hurt the others
Java exampleEach java Main you runmain, plus every Thread you start

Exam tip: “Threads share the heap and method area (classes, static fields); each thread has its own stack and program counter.” This one sentence answers most process-vs-thread questions. Also remember: the JVM exits when all non-daemon threads have finished.

3 Types and ways to use it

The threads you'll meet

The main thread

Created by the JVM to run main(). Everything you've written so far ran on it.

automatic

Your threads

Created with new Thread(…) and started with start() (Lesson 12.2).

user threads

Daemon threads

Background helpers (autosave, cleanup). The JVM doesn't wait for them when it exits.

setDaemon(true)

JVM's own threads

Garbage collector and JIT compiler threads run alongside yours, unseen (Module 8).

system

Meet the main thread

public class Main {
    public static void main(String[] args) {
        Thread me = Thread.currentThread();
        System.out.println("main runs on: " + me.getName());

        Thread helper = new Thread(() -> {});
        System.out.println(helper.getName() + ", state " + helper.getState()
                + ", daemon " + helper.isDaemon() + ", priority " + helper.getPriority());
    }
}
main runs on: main Thread-0, state NEW, daemon false, priority 5

An unnamed thread gets a default name (Thread-0, Thread-1 …). Before start() it is in state NEW: just an object on the heap, not yet running.

Concurrency vs parallelism

ConcurrencyParallelism
MeaningMany tasks in progress, taking turnsMany tasks running at the same instant
NeedsEven 1 core2 or more cores
Helps whenTasks wait for network, disk, usersTasks do heavy calculations
Canteen pictureOne cook switching between three dishesThree cooks, three dishes

How many cores can your program use? Ask the runtime (your number will differ):

public class Main {
    public static void main(String[] args) {
        System.out.println("CPU cores Java can use: " + Runtime.getRuntime().availableProcessors());
    }
}
CPU cores Java can use: 2

More threads isn't always faster. If you start 1,000 threads for heavy calculations on an 8-core machine, they just take turns, and switching between them costs time and memory (each thread has its own stack). For many tasks, use a thread pool (Lesson 12.6).

4 Step by step

From java Main to the last thread

  1. The OS starts a process

    Running java Main makes the operating system create a new process with its own memory. The JVM sets up the heap and the method area inside it.
  2. The JVM creates the main thread

    It also starts its own helper threads (garbage collection, JIT compilation). The main thread gets a stack and calls main(args): its first frame.
  3. Your code creates more threads

    Thread t = new Thread(() -> download("menu.json"));
    t.start();
    new Thread(…) only creates an object on the heap. start() creates the real thread: a new stack, registered with the scheduler.
  4. The scheduler shares the cores

    The OS decides which thread runs on which core and for how long, switching between them many times a second. You cannot predict the exact order: that's why output from different threads can interleave differently each run.
  5. Threads end; then the JVM exits

    A thread ends when its run code returns. When the last non-daemon thread (often main) ends, the JVM stops any daemon threads and the process exits.
5 See it happen

One worker vs three workers: both views

Left: the timeline your users feel. Right: inside the process, the shared heap, one stack per thread, and the CPU cores.

One thread vs several threads 6 steps
What you see download(a); download(b); download(c); download(a); download(b); download(c); download(a); download(b); download(c); new Thread(() -> download(a)).start(); … t1.join(); t2.join(); t3.join(); // all three done time → main a b c 3 s t1 a t2 b t3 c ≈ 1 s One thread, first download… …then the second… …then the third: 3 seconds. Three threads start together. main waits for all three. Same work, about a third of the time. myphatshala.in
Behind the screen one JVM process (its own memory) HEAP (shared) #1 images[3] {a, b, c} main stack t1 stack t2 stack t3 stack CPU cores core 1 core 2 main t1, t2 t3 waits its turn scheduler swaps them t1–t3 finished A process with its heap and one thread. main runs on one core. The other core sits idle. Each new thread gets its own stack. All threads write to the same heap. Threads end; their stacks go. myphatshala.in
6 Real-world use

Threads in real systems

Almost every serious Java program uses several threads, even when you don't create them yourself.

Watch it with an example: a banking app that never freezes

A customer taps “Download statement”. Creating the PDF takes a few seconds. Watch what happens with and without a background thread.

Statement download in the background 5 steps
Animated example phone screen Download Balance frozen… responsive ✓ ₹ 24,500 UI thread makePdf(); // 4 s new Thread(makePdf).start(); background thread building PDF… statement.pdf ready A tap on Download. Done on the UI thread: the app freezes. Hand the job to a new thread. The screen keeps responding. The PDF is ready; tell the user. myphatshala.in

1. Responsive apps

Mobile and desktop apps keep one thread for the screen and push slow work (network calls, files, image processing) to background threads, so the app never looks frozen.

tap “Refresh”→background thread→screen stays smooth

2. Web servers

A server handling bookings or payments serves many customers at once, typically handing each incoming request to a thread from a pool.

1,000 requests→thread pool→answered concurrently

3. Batch jobs that use every core

Month-end jobs (interest for lakhs of accounts, report generation) split the data into chunks and process the chunks in parallel on all cores.

10 lakh accounts→8 threads × chunks→done much sooner

4. Background helpers

Autosave, cache cleanup, metrics reporting and the JVM's own garbage collector run on helper (often daemon) threads while the main work goes on.

every 60 s→daemon thread→draft saved

Examples are simplified. Real apps usually use thread pools and frameworks rather than creating raw threads by hand (Lesson 12.6).

7 Run the code

Three downloads at once

public class Main {
    static String[] files = {"menu.json", "offers.json", "photo.jpg"};
    static int[] bytes = new int[3];

    static void download(int i) {
        bytes[i] = files[i].length() * 100;   // pretend work: size depends on the name
        System.out.println(Thread.currentThread().getName() + " downloaded " + files[i]);
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] workers = new Thread[3];
        for (int i = 0; i < 3; i++) {
            int k = i;
            workers[i] = new Thread(() -> download(k), "dl-" + k);
            workers[i].start();
        }
        for (Thread t : workers) {
            t.join();
        }
        System.out.println("All done: " + bytes[0] + " + " + bytes[1] + " + " + bytes[2] + " bytes");
    }
}
dl-0 downloaded menu.json dl-2 downloaded photo.jpg dl-1 downloaded offers.json All done: 900 + 1100 + 900 bytes

The three “downloaded” lines may come out in a different order each time you run it: the scheduler decides. The last line is always the same, because main waits with join() before printing.

  • int k = i;A lambda can only use local variables that never change. i changes every loop; k is a fresh copy per thread.
  • new Thread(() -> download(k), "dl-" + k)The code to run, and a name that shows up in logs.
  • workers[i].start()Creates the real thread. The loop continues immediately; it doesn't wait.
  • t.join()Waits for each worker before reading bytes.
8 Line by line

main starts a worker and waits for its answer

This trace is recorded from the real JVM and follows the main thread. Watch the Thread object on the heap change state, and the shared array receive a value written by the other thread.

Worked examples: real problems, solved and traced in memory

Three small programs in the style of real apps. The traces follow the main thread: watch Thread objects appear on the heap, change state, and leave their results in shared objects.

Example 1Food delivery · images

Prepare three menu photos at once

Problem statement

A food app must resize three dish photos before showing the menu. Do each one in its own thread, wait for all three, then print the new sizes. (Resizing is simulated by halving a number.)

Input
photo sizes in KB: 840, 620, 980
Expected output
420 310 490 KB

Approach

  1. Store the inputs and the results in two arrays on the heap.
  2. Create one thread per photo; each thread writes only its own result slot, so they never touch the same element.
  3. Start all threads, then join() each one before reading the results.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Banking · reports

Two threads fill one report object

Problem statement

A month-end report has two sections: total deposits and total withdrawals. Compute each section in a separate thread that writes into the same Report object, then print the report.

Input
deposits 5000, 12000, 800; withdrawals 2000, 450
Expected output
In 17800, out 2450, net 15350

Approach

  1. Create one Report object on the heap; both threads get a reference to it.
  2. Thread A sums deposits into report.in; thread B sums withdrawals into report.out. Different fields, so no clash.
  3. Join both threads, then print. The report object shows both threads' work.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Notes app · autosave

A daemon autosave thread doesn't keep the app alive

Problem statement

A notes app runs an autosave helper in the background forever. When the user closes the app, the program must end without waiting for the helper. Mark the helper as a daemon thread and show that the program still ends.

Input
(no input)
Expected output
autosave daemon? true
main is done; the JVM exits now

Approach

  1. Create the autosave thread with an endless loop that sleeps between saves.
  2. Call setDaemon(true) before start().
  3. When main ends, only daemon threads are left, so the JVM exits.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 12.1 in one screen

  • Process = running program with its own memory. Thread = path of execution inside a process.
  • Threads share the heap and static fields; each has its own stack and program counter.
  • Every Java program starts on the main thread; the JVM also runs GC and JIT threads.
  • new Thread(…) makes an object (NEW); start() makes it run; join() waits for it.
  • Concurrency = taking turns; parallelism = truly simultaneous on several cores.
  • The scheduler picks the order: output from threads can interleave differently each run.
  • The JVM exits when all non-daemon threads end; daemon threads are stopped.

Interview and viva questions

What is the difference between a process and a thread?

A process is a running program with its own isolated memory and resources. A thread is a unit of execution inside a process. Threads of the same process share heap memory and resources, which makes communication easy and creation cheap, but each thread has its own stack and program counter.

What do threads share, and what do they not share?

Shared: heap objects, static fields, loaded classes, open files. Not shared: the stack (method frames, local variables, parameters) and the program counter. That's why local variables are naturally thread-safe and shared objects are not.

What is the difference between concurrency and parallelism?

Concurrency means multiple tasks make progress in overlapping time periods, possibly by taking turns on one core. Parallelism means tasks execute at the same instant on multiple cores. Parallelism is one way to achieve concurrency.

What is a daemon thread?

A low-priority background thread that does not prevent the JVM from exiting. When only daemon threads remain, the JVM shuts down and stops them abruptly. Use setDaemon(true) before start(); never use daemons for work that must complete.

Why can't you predict the order of output from two threads?

The operating system's scheduler decides when each thread runs and for how long, based on load, cores and timing. To get a guaranteed order you must coordinate threads explicitly, for example with join(), locks or queues.

Practice problems

Start, name and join threads, and let them share results through the heap. Every solution waits with join() before printing, so the output is always the same. The last three are business tasks.

P1Easy

Name of the current thread

Print the name of the thread that runs main.

Input
(none)
Expected output
Running on: main
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        System.out.println("Running on: " + Thread.currentThread().getName());
    }
}
Running on: main

How it works: the JVM runs main on a thread called "main". Thread.currentThread() returns the thread executing the current line.

P2Easy

Start a named thread and wait for it

Create a thread named "greeter" that prints Hello from greeter. Start it, wait for it, then print main ends.

Input
(none)
Expected output
Hello from greeter
main ends
Show solution and explanation
public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread g = new Thread(() -> System.out.println("Hello from " + Thread.currentThread().getName()), "greeter");
        g.start();
        g.join();
        System.out.println("main ends");
    }
}
Hello from greeter main ends

How it works: the second argument of the constructor names the thread. join() guarantees the greeting is printed before "main ends".

P3Easy

Default thread names

Create two threads without names and print their default names and states.

Input
(none)
Expected output
Thread-0 NEW
Thread-1 NEW
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        Thread a = new Thread(() -> {});
        Thread b = new Thread(() -> {});
        System.out.println(a.getName() + " " + a.getState());
        System.out.println(b.getName() + " " + b.getState());
    }
}
Thread-0 NEW Thread-1 NEW

How it works: unnamed threads get names Thread-0, Thread-1 … in creation order. Before start() they are in state NEW. Name your threads: it makes logs readable.

P4Medium

Sum 1 to 1000 in two halves

Use two threads: one sums 1–500, the other 501–1000. Each stores its part in a shared array. Print both parts and the total.

Input
1..1000
Expected output
125250 + 375250 = 500500
Show solution and explanation
public class Main {
    static long[] part = new long[2];

    public static void main(String[] args) throws InterruptedException {
        Thread low = new Thread(() -> { for (int i = 1; i <= 500; i++) part[0] += i; });
        Thread high = new Thread(() -> { for (int i = 501; i <= 1000; i++) part[1] += i; });
        low.start();
        high.start();
        low.join();
        high.join();
        System.out.println(part[0] + " + " + part[1] + " = " + (part[0] + part[1]));
    }
}
125250 + 375250 = 500500

How it works: each thread writes a different array slot, so they never write the same memory. After both joins, main can safely read the results. Splitting work into independent pieces is the basic idea of parallel processing.

P5Medium

Largest value, split across threads

Find the largest value in an array of 8 numbers by giving each half to a different thread, then comparing the two answers.

Input
[14, 92, 33, 7, 61, 88, 45, 19]
Expected output
Halves: 92, 88; max 92
Show solution and explanation
public class Main {
    static int[] data = {14, 92, 33, 7, 61, 88, 45, 19};
    static int[] best = new int[2];

    static void maxOf(int slot, int from, int to) {
        int m = data[from];
        for (int i = from + 1; i < to; i++) m = Math.max(m, data[i]);
        best[slot] = m;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(() -> maxOf(0, 0, 4));
        Thread b = new Thread(() -> maxOf(1, 4, 8));
        a.start();
        b.start();
        a.join();
        b.join();
        System.out.println("Halves: " + best[0] + ", " + best[1] + "; max " + Math.max(best[0], best[1]));
    }
}
Halves: 92, 88; max 92

How it works: a normal method does the work; each thread just calls it with different ranges. Each thread has its own stack, so the local m in one thread can't interfere with the other's.

P6Business problem

Store totals in parallel

A chain has 3 stores. Each store's daily bills are in an array. Compute each store's total in its own thread and print a summary.

Input
Pune {450, 1200, 300}; Nagpur {800, 150}; Nashik {990, 60, 75, 300}
Expected output
Pune: Rs 1950
Nagpur: Rs 950
Nashik: Rs 1425
Show solution and explanation
public class Main {
    static String[] stores = {"Pune", "Nagpur", "Nashik"};
    static int[][] bills = {{450, 1200, 300}, {800, 150}, {990, 60, 75, 300}};
    static int[] totals = new int[3];

    public static void main(String[] args) throws InterruptedException {
        Thread[] t = new Thread[3];
        for (int s = 0; s < 3; s++) {
            int k = s;
            t[s] = new Thread(() -> { for (int b : bills[k]) totals[k] += b; }, stores[s]);
            t[s].start();
        }
        for (Thread x : t) x.join();
        for (int s = 0; s < 3; s++) System.out.println(stores[s] + ": Rs " + totals[s]);
    }
}
Pune: Rs 1950 Nagpur: Rs 950 Nashik: Rs 1425

How it works: one thread per store, each writing only its own slot. Naming each thread after its store makes logs and thread dumps easy to read in production.

P7Business problem

GST for two halves of an order list

Compute 18% GST on 6 order amounts, using one thread for the first three and another for the last three. Print the GST per order in the original order.

Input
[1000, 250, 4999, 120, 760, 3300]
Expected output
Order 1: GST 180.0
Order 2: GST 45.0
Order 3: GST 899.82
Order 4: GST 21.6
Order 5: GST 136.8
Order 6: GST 594.0
Show solution and explanation
public class Main {
    static double[] amount = {1000, 250, 4999, 120, 760, 3300};
    static double[] gst = new double[6];

    static void tax(int from, int to) {
        for (int i = from; i < to; i++) gst[i] = Math.round(amount[i] * 18) / 100.0;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(() -> tax(0, 3));
        Thread b = new Thread(() -> tax(3, 6));
        a.start();
        b.start();
        a.join();
        b.join();
        for (int i = 0; i < 6; i++) System.out.println("Order " + (i + 1) + ": GST " + gst[i]);
    }
}
Order 1: GST 180.0 Order 2: GST 45.0 Order 3: GST 899.82 Order 4: GST 21.6 Order 5: GST 136.8 Order 6: GST 594.0

How it works: results are stored by index, so the printing order doesn't depend on which thread finished first. Math.round(x * 18) / 100.0 rounds the tax to paise.

P8Business problem

Background audit logger that doesn't block shutdown

Start a daemon thread named "audit" that would write logs forever, record two transactions on main, and end the program cleanly.

Input
two transactions
Expected output
TXN-1 Rs 500 recorded
TXN-2 Rs 120 recorded
audit is daemon: true
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        Thread audit = new Thread(() -> {
            while (true) {
                try { Thread.sleep(10_000); } catch (InterruptedException e) { return; }
            }
        }, "audit");
        audit.setDaemon(true);
        audit.start();
        System.out.println("TXN-1 Rs 500 recorded");
        System.out.println("TXN-2 Rs 120 recorded");
        System.out.println(audit.getName() + " is daemon: " + audit.isDaemon());
    }
}
TXN-1 Rs 500 recorded TXN-2 Rs 120 recorded audit is daemon: true

How it works: the JVM exits when all non-daemon threads have ended. A daemon thread is a helper that never keeps the program alive. Never use daemons for work that must finish (like saving data): they are stopped abruptly.

Real-world scenario questions (asked in company interviews)

Interviewers use threads questions to see whether you understand what runs where, and what can go wrong.

Mobile app · UXFresher

The app hangs on the payment screen

Users report that after tapping “Pay”, the app becomes unresponsive for 5–8 seconds. The code calls the payment gateway directly inside the button's click handler. What's going on, and what would you change?

The interviewer is checking: that you know the UI runs on one thread and slow work must move off it.

Show a strong answer
  • The click handler runs on the UI thread. A blocking network call there stops the screen from redrawing or reacting.
  • Move the gateway call to a background thread (or a thread pool / async API), show a progress indicator, and update the screen when the result comes back.
  • Disable the Pay button while the call is in flight so the user can't pay twice.

Avoid: “Make the network faster.” The design is the problem, not the speed.

Backend · capacityJunior

One thread per request, 20,000 users

A booking service creates a brand-new thread for every incoming request. During a festival sale traffic jumps to 20,000 concurrent requests and the server runs out of memory. Explain why and suggest a fix.

The interviewer is checking: that threads cost memory and should be pooled.

Show a strong answer
  • Each platform thread reserves its own stack (often hundreds of KB to 1 MB). Thousands of threads use gigabytes and spend time switching.
  • Use a bounded thread pool with a queue (Lesson 12.6), or Java 21 virtual threads for I/O-heavy work.
  • Add back-pressure: reject or queue excess requests instead of crashing.

Avoid: just raising the heap size; stacks aren't even on the heap.

Fintech · data lossJunior

The audit log is sometimes empty

A tool records transactions, and a background thread writes them to an audit file. Sometimes, after the program ends, the last few entries are missing. The background thread was created with setDaemon(true). Why?

The interviewer is checking: JVM exit rules and daemon threads.

Show a strong answer
  • When main ends, only the daemon is left, so the JVM exits immediately and kills it mid-write.
  • Use a normal thread and signal it to finish, then join() it; or use an executor and call shutdown() + awaitTermination().
  • Flush and close the file in the writer (try-with-resources).

Avoid: adding Thread.sleep at the end of main and hoping it's long enough.

Analytics · performanceMid

“We added threads and nothing got faster”

A report job that calculates statistics for 50 lakh rows was changed to use 200 threads on a 4-core server. It got slightly slower. Explain.

The interviewer is checking: CPU-bound vs I/O-bound work and core limits.

Show a strong answer
  • The work is CPU-bound: only 4 threads can actually run at a time. The other 196 just wait, and switching between them adds overhead.
  • For CPU work, use about as many threads as cores (availableProcessors()), each on a chunk of data.
  • Many threads help only when they spend most of their time waiting on I/O.

Avoid: “more threads = more speed.” Measure, and match threads to the kind of work.