Concurrency & Threads
879 words
4 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Concurrency & Threads ## 🎯 Learning Objectives - Create threads by extending Thread and implementing Runnable - Understand the thread lifecycle (states) - Use sleep, join, and interrupt for thread coordination - Distinguish daemon and user threads - Avoid common threading pitfalls ## 1. What Problem Do Threads So...

Concurrency & Threads
🎯 Learning Objectives
- Create threads by extending Thread and implementing Runnable
- Understand the thread lifecycle (states)
- Use sleep, join, and interrupt for thread coordination
- Distinguish daemon and user threads
- Avoid common threading pitfalls
1. What Problem Do Threads Solve?
Without threads, a program does one thing at a time. If one operation blocks (network request, file read, user input), the entire program freezes. Threads enable concurrency — multiple tasks making progress simultaneously.
Example: A web server handling 1000 requests. Without threads, each request must complete before the next starts. With threads, each request gets its own thread, allowing parallel processing.
2. Creating Threads — Two Approaches
2.1 Extending Thread
javaclass MyThread extends Thread { @Override public void run() { System.out.println("Thread running: " + getName()); } } // Usage: MyThread t = new MyThread(); t.start(); // NOT t.run()! start() creates a new thread
2.2 Implementing Runnable (Preferred)
javaclass MyTask implements Runnable { @Override public void run() { System.out.println("Task running in: " + Thread.currentThread().getName()); } } // Usage: Thread t = new Thread(new MyTask()); t.start(); // Lambda version: Thread t = new Thread(() -> System.out.println("Running")); t.start();
Why Runnable is preferred: Your class can extend another class (interface is flexible). Also, Runnable separates the task from the execution mechanism.
3. Thread Lifecycle
(Diagram)
States:
- NEW: Created but not started (
new Thread()) - RUNNABLE: Ready to run, waiting for CPU scheduler
- RUNNING: Actually executing (
run()method body) - BLOCKED/WAITING: Waiting (sleep, I/O, lock, join)
- TERMINATED: Completed (
run()returned)
4. Important Thread Methods
4.1 sleep — Pause Execution
javaThread.sleep(1000); // Sleep for 1000 ms (1 second) // throws InterruptedException — must handle
4.2 join — Wait for Thread Completion
javaThread worker = new Thread(() -> { // Do work... }); worker.start(); worker.join(); // Main thread waits for worker to finish System.out.println("Worker done!");
4.3 interrupt — Request Thread to Stop
javaThread worker = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { // Keep working } }); worker.start(); Thread.sleep(100); worker.interrupt(); // Request interruption
5. Daemon vs User Threads
- User threads: Keep the JVM alive. JVM exits only when all user threads finish.
- Daemon threads: Background threads. JVM can exit while daemon threads are running.
javaThread t = new Thread(() -> { while (true) { /* background task */ } }); t.setDaemon(true); // Must be set BEFORE start() t.start(); // JVM can exit even though t is running
6. Common Pitfalls
Pitfall 1: Calling run() Instead of start()
javaThread t = new Thread(() -> System.out.println("Working")); t.run(); // Runs in CURRENT thread, not new thread!
Fix: Call
t.start() to create a new thread.Pitfall 2: Race Conditions (Unsyncronized Access)
javaclass Counter { private int count = 0; public void increment() { count++; } // Not atomic! } // Two threads calling increment() simultaneously may lose updates
Pitfall 3: Thread Starvation / Deadlock
Two threads waiting for locks held by the other — programs hangs forever.
7. Practice Questions
Q1: What is the output?javaThread t = new Thread(() -> System.out.println("Hello")); t.start(); System.out.println("World");Answer: EitherWorld HelloorHello World— order depends on thread scheduler. Q2: Difference between start() and run()?Answer:start()creates a new thread and callsrun()in that thread.run()just executes the code in the current thread (no new thread). Q3: What does join() do?Answer: The calling thread waits (blocks) until the thread on whichjoin()was called finishes execution. It's used for coordination — "don't proceed until this thread is done." Q4: Can you restart a terminated thread?Answer: No. Once a thread'srun()completes, it's in TERMINATED state and cannot be restarted. Callingstart()again throwsIllegalThreadStateException. Q5: What is a daemon thread?Answer: A background thread that doesn't keep the JVM alive. When all user threads finish, the JVM exits, killing any remaining daemon threads. Used for housekeeping tasks (garbage collection, monitoring). Q6: What happens when sleep(1000) is called?Answer: The thread enters TIMED_WAITING state for approximately 1000ms. It releases the CPU but does NOT release any locks held. After the time elapses, it becomes RUNNABLE again. Q7: What is the difference between Runnable and Callable?Answer:Runnable.run()returnsvoidand cannot throw checked exceptions.Callable.call()returns a value and can throw checked exceptions. Callable is used withExecutorServiceandFuture. Q8: Why implement Runnable instead of extending Thread?Answer: (1) Java doesn't support multiple class inheritance — extending Thread prevents extending anything else. (2) Runnable separates task from execution. (3) Runnable can be used with thread pools (ExecutorService).
📐 Key Concepts
| Method | Purpose |
|---|---|
start() | Create new thread and execute run() |
run() | Task code (don't call directly) |
sleep(ms) | Pause current thread |
join() | Wait for thread to finish |
interrupt() | Request thread to stop |
isAlive() | Check if thread is still running |