Skip to content
QuizMaker logoQuizMaker
Activity
Java Programming: From Zero to Enterprise
4. Advanced Java & Frameworks
1. Getting Started with Java & the JVM
2. Data Types & Variables
3. Control Flow: Ifs & Loops
4. String Manipulation in Depth
5. Methods (Functions) Architecture
6. Arrays & The Enhanced For Loop
7. User Input via Scanner
8. Mathematical Operations & The Math Class
9. Operators in Depth
10. Block Scope & Variable Lifecycles
11. Introduction to Object-Oriented Programming
12. Classes & Instances Deep Dive
13. Constructors
14. Encapsulation & The 'this' Keyword
15. Inheritance: Extending Functionality
16. Polymorphism & Method Overriding
17. Abstraction & Abstract Classes
18. Interfaces: The Ultimate Contract
19. Packages & Access Modifiers
20. Enums (Enumerations)
21. Exceptions: Handling Runtime Errors
22. The 'throw' and 'throws' keywords
23. Dates, Times, and Formatting
24. Enumerable Data Structures
25. LinkedLists: The Alternative
26. HashMaps: Key-Value Architecture
27. HashSets: The Art of Uniqueness
28. Iterator: Safe Collection Traversal
29. Wrapper Classes & Autoboxing
30. Basic File I/O
31. Generics: Type-Safe Templates
32. Lambda Expressions & Functional Interfaces
33. The Stream API: Functional Data Pipelines
34. Optional: Beating the NullPointerException
35. Multithreading & Concurrency Basics
36. JDBC: Connecting to SQL Databases
37. Annotations & Reflection
38. The JVM Garbage Collector
39. Introduction to Spring Boot
40. Unit Testing with JUnit
41. Java Collections for DSA
CONTENTS

35. Multithreading & Concurrency Basics

Doing ten things at exactly the same time.

Java Programming: From Zero to Enterprise
4. Advanced Java & Frameworks
February 22, 2026
65
A

[!NOTE] Historically, your Java program executed on a single "Main Thread". It processed line 1, then line 2. If line 2 was a 10-second database query, the application froze for 10 seconds before hitting line 3.

To build high-performance web servers (which handle 10,000 user requests simultaneously), we must execute code Concurrently across multiple CPU threads.

The Physical Thread Array

When a user runs a Java program, the JVM spawns an independent "Main Thread".

You can spawn your own background threads by:

  1. Creating a class that implements the Runnable interface.
  2. Writing the heavy logic inside the run() method.
  3. Handing that object to a raw Thread object and executing .start().
// 1. Build the heavy background task logic
class HeavyTask implements Runnable {
    public void run() {
        System.out.println("Beginning huge 10-second data processing on Thread: " + Thread.currentThread().getName());
        // ... intensive CPU math ...
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Main Application Booting Up...");

        // 2. Instantiate and hook it into a physical Thread!
        Thread myWorkerThread = new Thread(new HeavyTask());
        
        // 3. START IT! This instantly detaches vertically from the main thread!
        myWorkerThread.start();
        
        System.out.println("Main application continues immediately without waiting!");
    }
}

Thread Pools & The ExecutorService

Raw threading is extremely dangerous. Spinning up millions of threads (e.g., one per user click) will crash the entire operating system, as threads inherently consume RAM.

Modern Java developers almost never use new Thread(). They use an ExecutorService (a Thread Pool). You tell the system: "I'm giving you a pool of exactly 10 threads. Here are 5,000 tasks. Recycle those 10 threads to churn through the block."

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        
        // 1. Request a fixed squad of 5 heavily optimized worker threads
        ExecutorService pool = Executors.newFixedThreadPool(5);

        // 2. Submit 100 heavy jobs to the squad. They will balance the work perfectly!
        for (int i = 0; i < 100; i++) {
            pool.submit(new HeavyTask());
        }

        // 3. Order the pool to shutdown gracefully after the last job finishes.
        pool.shutdown();
    }
}

[!CAUTION] Race Conditions: If Thread A and Thread B try to update the exact same int bankBalance = 100 at the precise exact millisecond, they interfere and overwrite each other, causing money to vanish! You must use the synchronized keyword or AtomicInteger variables to lock memory addresses from being concurrently touched by competing threads.

Concurrency Is About Shared State

Running work on multiple threads is easy. Making shared data safe is the hard part. Most concurrency bugs happen when two threads read and write the same state without coordination.

Race Condition Example

class Counter {
    private int value = 0;

    void increment() {
        value++;
    }
}

value++ looks like one operation, but it is read, add, and write. Two threads can interleave those steps and lose updates.

Safer Counter

class Counter {
    private final AtomicInteger value = new AtomicInteger();

    void increment() {
        value.incrementAndGet();
    }
}

Practical Guidance

  • Prefer immutable data when possible.
  • Use thread pools instead of creating unlimited raw threads.
  • Use concurrent collections for shared collection access.
  • Keep synchronized sections small and easy to reason about.

Mini Practice

Create two tasks that increment a shared counter 1,000 times each. First observe the unsafe result with int, then fix it with AtomicInteger.

Practice Lab: Counter Race Condition

Observe why shared mutable state needs protection.

  1. Create a shared counter using plain int.
  2. Start two tasks that increment it 1,000 times each.
  3. Print the final value and observe that it may be incorrect.
  4. Replace the counter with AtomicInteger.
  5. Run again and compare the result.

Goal: Understand race conditions and one safe atomic alternative.

Revision Checkpoint

  • Thread: Independent path of execution.
  • Runnable: Task that can run on a thread.
  • ExecutorService: Manages reusable thread pools.
  • Race condition: Multiple threads access shared state unsafely.
  • Atomic tools: Help protect simple shared updates.

Before the quiz: Explain why value++ is not safely atomic across threads.

Share this article

Share on TwitterShare on LinkedInShare on FacebookShare on WhatsAppShare on Email

Test your knowledge

Take a quick quiz based on this chapter.

hardJava
Quiz: Multithreading
10 questions5 min
Lesson 5 of 11 in 4. Advanced Java & Frameworks
Previous in 4. Advanced Java & Frameworks
34. Optional: Beating the NullPointerException
Next in 4. Advanced Java & Frameworks
36. JDBC: Connecting to SQL Databases
Back to Java Programming: From Zero to Enterprise
Back to moduleCategories