Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • 📝 Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • 📝 Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • 📝 Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • 📝 Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • 📝 While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • 📝 For Each Assignments
    • 📝 All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • 📝 Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • 📝 Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • 📝 Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • 📝 Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • 📝 Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • 📝 Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • 📝 Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • 📝 Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • 📝 Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • 📝 Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • 📝 Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • 📝 Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • 📝 Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • 📝 Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • 📝 Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • 📝 Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • 📝 Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • 📝 Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • 📝 Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Creating Threads

Python Creating Threads - Complete Guide

Learn how to create and manage threads in Python.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
Read Time: 12 minutes Level: Intermediate Topic: Python Threading Focus: Thread Creation Methods
On this page:
  • Why Create Threads?
  • Method 1: Function Target
  • Method 2: Subclassing Thread
  • Method 3: Thread Pool Executor
  • Thread Lifecycle
  • Method Comparison
  • Real-World Example
  • Best Practices
  • Try It Yourself
  • Quiz
  • FAQ
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • Function Target — simplest way to create threads
  • Subclassing Thread — object-oriented approach
  • Thread Pool Executor — managing many threads
  • Thread Lifecycle — from creation to completion
  • When to use each method — choosing the right approach

Why Create Threads?

Creating threads allows your program to do multiple things at once. It's like having multiple workers in a factory instead of just one.

🏭 Think of it like a factory assembly line.

Without threads: One worker does everything — takes parts, assembles, packages. Slow and inefficient.

With threads: Multiple workers do different tasks simultaneously — one takes parts, another assembles, another packages. Fast and efficient!

💡 Key concept: Creating a thread is like hiring a new worker. Each thread can do its own task independently.

1

Ways to Create Threads

# ============================================================
# THREE WAYS TO CREATE THREADS
# ============================================================

print("""
┌─────────────────────────────────────────────────────────────────┐
│ METHOD 1: FUNCTION TARGET                                     │
│ - Simplest and most common                                    │
│ - Pass a function to Thread constructor                       │
│ - Good for simple tasks                                      │
├─────────────────────────────────────────────────────────────────┤
│ METHOD 2: SUBCLASSING THREAD                                  │
│ - Create a class that inherits from Thread                   │
│ - Override the run() method                                  │
│ - Good for complex threads with state                       │
├─────────────────────────────────────────────────────────────────┤
│ METHOD 3: THREAD POOL EXECUTOR                                │
│ - Manage multiple threads efficiently                        │
│ - Reuses threads for many tasks                              │
│ - Best for many small tasks                                  │
└─────────────────────────────────────────────────────────────────┘
""")

Key point: Choose the method based on your needs. Function target is simplest; subclassing gives more control; thread pools are efficient for many tasks.

Quick Check: What are the three ways to create threads in Python? (Answer: Function target, subclassing Thread, and Thread Pool Executor)

Method 1: Function Target

2

The Simplest Way to Create Threads

# ============================================================
# METHOD 1: FUNCTION TARGET
# ============================================================

import threading
import time

# ============================================================
# BASIC EXAMPLE
# ============================================================

def print_numbers():
    """Print numbers from 1 to 5"""
    for i in range(1, 6):
        print(f"Number: {i}")
        time.sleep(0.3)

def print_letters():
    """Print letters from A to E"""
    for letter in ['A', 'B', 'C', 'D', 'E']:
        print(f"Letter: {letter}")
        time.sleep(0.3)

# Create threads
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

# Start threads
thread1.start()
thread2.start()

# Wait for threads to finish
thread1.join()
thread2.join()

print("Both threads finished!")

# ============================================================
# THREAD WITH ARGUMENTS
# ============================================================

def greet(name, times, delay=0.5):
    """Greet someone multiple times"""
    for i in range(times):
        print(f"Hello, {name}! (Greeting {i+1})")
        time.sleep(delay)

# Create thread with arguments
thread = threading.Thread(
    target=greet,
    args=("Alice", 3),
    kwargs={"delay": 0.3}
)

thread.start()
thread.join()

# ============================================================
# THREAD WITH RETURN VALUE (Using a list)
# ============================================================

def calculate_square(n, result_list, index):
    """Calculate square and store in list"""
    result = n * n
    result_list[index] = result
    print(f"Square of {n} is {result}")

results = [0] * 5
threads = []

for i in range(5):
    t = threading.Thread(target=calculate_square, args=(i+1, results, i))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print(f"Results: {results}")

Function target key points:

  • Simple — just pass a function
  • args — pass positional arguments
  • kwargs — pass keyword arguments
  • No return — threads don't return values directly

Quick Check: How do you pass arguments to a thread created with function target? (Answer: Using args and kwargs parameters)

Method 2: Subclassing Thread

3

Object-Oriented Thread Creation

# ============================================================
# METHOD 2: SUBCLASSING THREAD
# ============================================================

import threading
import time

# ============================================================
# BASIC SUBCLASS
# ============================================================

class MyThread(threading.Thread):
    """A custom thread class"""
    
    def __init__(self, name, delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay
    
    def run(self):
        """Code to run in the thread"""
        print(f"Thread {self.name} starting...")
        time.sleep(self.delay)
        print(f"Thread {self.name} finished!")

# Create and start threads
t1 = MyThread("A", 2)
t2 = MyThread("B", 3)

t1.start()
t2.start()
t1.join()
t2.join()

# ============================================================
# ADVANCED SUBCLASS WITH STATE
# ============================================================

class WorkerThread(threading.Thread):
    """Worker thread with state and progress tracking"""
    
    def __init__(self, worker_id, task_count):
        threading.Thread.__init__(self)
        self.worker_id = worker_id
        self.task_count = task_count
        self.completed = 0
        self.is_running = True
    
    def run(self):
        """Process tasks"""
        print(f"Worker {self.worker_id} started")
        
        for i in range(self.task_count):
            if not self.is_running:
                break
            
            # Simulate work
            time.sleep(0.5)
            self.completed += 1
            print(f"Worker {self.worker_id}: {self.completed}/{self.task_count}")
        
        print(f"Worker {self.worker_id} finished ({self.completed} tasks)")
    
    def stop(self):
        """Stop the worker"""
        self.is_running = False

# Create workers
workers = []
for i in range(3):
    w = WorkerThread(i+1, 5)
    workers.append(w)
    w.start()

# Let them work
time.sleep(2)

# Stop one worker early
workers[1].stop()

# Wait for all workers
for w in workers:
    w.join()

print("All workers finished!")

# ============================================================
# COMPARISON: SUBCLASS vs FUNCTION TARGET
# ============================================================

print("""
┌─────────────────────────────────────────────────────────────────┐
│ SUBCLASSING THREAD:                                            │
│ ✅ More object-oriented                                        │
│ ✅ Can have state and methods                                 │
│ ✅ Better for complex threads                                 │
│ ✅ Can be extended                                           │
├─────────────────────────────────────────────────────────────────┤
│ FUNCTION TARGET:                                              │
│ ✅ Simpler and more Pythonic                                  │
│ ✅ Less boilerplate code                                      │
│ ✅ Good for simple tasks                                      │
│ ✅ Easier to understand                                       │
└─────────────────────────────────────────────────────────────────┘
""")

Subclassing Thread key points:

  • run() — override this method
  • __init__ — pass custom data
  • State — can maintain internal state
  • Methods — can have custom methods

Quick Check: What method do you override when subclassing Thread? (Answer: run())

Method 3: Thread Pool Executor

4

Managing Many Threads Efficiently

# ============================================================
# METHOD 3: THREAD POOL EXECUTOR
# ============================================================

import concurrent.futures
import time
import random

# ============================================================
# BASIC THREAD POOL
# ============================================================

def process_task(task_id):
    """Simulate processing a task"""
    delay = random.uniform(0.5, 2.0)
    print(f"Task {task_id}: Starting (will take {delay:.2f}s)")
    time.sleep(delay)
    result = f"Task {task_id} completed in {delay:.2f}s"
    print(f"Task {task_id}: Finished")
    return result

print("Using ThreadPoolExecutor with 3 workers:")

with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    # Submit tasks
    futures = []
    for i in range(10):
        future = executor.submit(process_task, i)
        futures.append(future)
    
    # Get results as they complete
    for future in concurrent.futures.as_completed(futures):
        try:
            result = future.result()
            print(f"Result: {result}")
        except Exception as e:
            print(f"Error: {e}")

# ============================================================
# MAP FUNCTION - SIMPLER WAY
# ============================================================

def square(n):
    """Calculate square of a number"""
    time.sleep(random.uniform(0.1, 0.3))
    return n * n

print("\nUsing map with ThreadPoolExecutor:")

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    numbers = [1, 2, 3, 4, 5, 6, 7, 8]
    results = executor.map(square, numbers)
    
    for num, result in zip(numbers, results):
        print(f"{num}² = {result}")

# ============================================================
# HANDLING EXCEPTIONS
# ============================================================

def risky_task(n):
    """A task that might fail"""
    if n == 5:
        raise ValueError(f"Task {n} failed!")
    time.sleep(0.1)
    return f"Task {n} succeeded"

print("\nHandling exceptions:")

with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    futures = {executor.submit(risky_task, i): i for i in range(10)}
    
    for future in concurrent.futures.as_completed(futures):
        task_id = futures[future]
        try:
            result = future.result()
            print(f"Task {task_id}: {result}")
        except Exception as e:
            print(f"Task {task_id}: Failed - {e}")

print("""
┌─────────────────────────────────────────────────────────────────┐
│ THREAD POOL EXECUTOR BENEFITS:                                 │
├─────────────────────────────────────────────────────────────────┤
│ • Reuses threads (no creation overhead)                       │
│ • Limits the number of threads                               │
│ • Manages thread lifecycle                                   │
│ • Easy to submit many tasks                                  │
│ • Handles exceptions well                                    │
│ • Clean API (submit, map, as_completed)                     │
└─────────────────────────────────────────────────────────────────┘
""")

Thread Pool Executor key points:

  • Reuses threads — no creation overhead
  • Limits threads — prevents overload
  • submit() — submit individual tasks
  • map() — apply function to iterable
  • as_completed() — get results as they finish

Quick Check: What module provides ThreadPoolExecutor? (Answer: concurrent.futures)

Thread Lifecycle

5

Understanding the Thread Lifecycle

# ============================================================
# THREAD LIFECYCLE
# ============================================================

import threading
import time

class LifecycleDemo:
    """Demonstrate thread lifecycle"""
    
    def __init__(self):
        self.running = True
    
    def worker(self):
        """Worker thread demonstrating lifecycle"""
        print("1. Thread created (NEW state)")
        print("2. Thread starting (RUNNABLE state)")
        
        count = 0
        while self.running and count < 5:
            count += 1
            print(f"   Running... ({count})")
            time.sleep(0.5)
        
        print("3. Thread completed (TERMINATED state)")
    
    def run_demo(self):
        """Run the lifecycle demo"""
        # Create thread (NEW state)
        t = threading.Thread(target=self.worker)
        print("Thread object created (NEW)")
        
        # Start thread (RUNNABLE state)
        t.start()
        print("Thread started (RUNNABLE)")
        
        # Check if running
        print(f"Is thread alive? {t.is_alive()}")
        
        # Wait for completion
        time.sleep(1.5)
        
        # Stop the thread
        self.running = False
        print("Signaling thread to stop")
        
        # Wait for thread to finish (TERMINATED state)
        t.join()
        print(f"Is thread alive? {t.is_alive()}")
        print("Thread terminated")

# ============================================================
# THREAD STATES
# ============================================================

print("=" * 60)
print("THREAD STATES")
print("=" * 60)

print("""
┌─────────────────────────────────────────────────────────────────┐
│ THREAD STATES                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. NEW                                                        │
│     - Thread object created but not started                    │
│     - t = threading.Thread(target=func)                       │
│                                                                 │
│  2. RUNNABLE                                                   │
│     - Thread is running or ready to run                       │
│     - t.start()                                               │
│                                                                 │
│  3. BLOCKED                                                    │
│     - Thread is waiting for a resource                        │
│     - Waiting for lock, I/O, sleep, join                    │
│                                                                 │
│  4. TERMINATED                                                 │
│     - Thread has finished execution                           │
│     - run() method completed                                  │
└─────────────────────────────────────────────────────────────────┘
""")

# Run the demo
print("=" * 60)
print("LIFECYCLE DEMONSTRATION")
print("=" * 60)

demo = LifecycleDemo()
demo.run_demo()

Thread lifecycle key points:

  • NEW — created but not started
  • RUNNABLE — running or ready to run
  • BLOCKED — waiting for resource
  • TERMINATED — finished execution

Quick Check: What state is a thread in when it's created but not started? (Answer: NEW)

Method Comparison

6

Choosing the Right Method

Feature Function Target Subclassing Thread ThreadPoolExecutor
Simplicity Very Simple Moderate Moderate
Code Reuse Low High Medium
State Management Low High Medium
Many Tasks Poor Poor Excellent
Performance Good Good Excellent
Best For Simple tasks Complex threads Many tasks

Recommendations:

  • Function Target — for simple, one-off tasks
  • Subclassing Thread — for complex, reusable threads
  • ThreadPoolExecutor — for many small tasks

Quick Check: Which method is best for many small tasks? (Answer: ThreadPoolExecutor)

Real-World Example

7

Complete Threaded Application

# ============================================================
# REAL-WORLD: THREADED DATA PROCESSOR
# ============================================================

import threading
import time
import random
import queue
from concurrent.futures import ThreadPoolExecutor

class DataProcessor:
    """Real-world threaded data processor"""
    
    def __init__(self, num_workers=4):
        self.num_workers = num_workers
        self.task_queue = queue.Queue()
        self.results = []
        self.lock = threading.Lock()
        self.running = False
    
    # ============================================================
    # WORKER METHODS
    # ============================================================
    
    def worker_function(self, worker_id):
        """Worker using function target"""
        print(f"Worker {worker_id}: Starting")
        
        while self.running:
            try:
                # Get task from queue
                task = self.task_queue.get(timeout=1)
                if task is None:
                    break
                
                # Process task
                result = self.process_task(worker_id, task)
                
                # Store result
                with self.lock:
                    self.results.append(result)
                
                self.task_queue.task_done()
                
            except queue.Empty:
                continue
        
        print(f"Worker {worker_id}: Stopping")
    
    def process_task(self, worker_id, task):
        """Process a single task"""
        print(f"Worker {worker_id}: Processing {task}")
        time.sleep(random.uniform(0.2, 0.6))
        return f"Processed {task} by worker {worker_id}"
    
    # ============================================================
    # THREAD CREATION METHODS
    # ============================================================
    
    def create_workers_function_target(self):
        """Create workers using function target"""
        threads = []
        for i in range(self.num_workers):
            t = threading.Thread(
                target=self.worker_function,
                args=(i,),
                name=f"Worker-{i}"
            )
            threads.append(t)
            t.start()
        return threads
    
    def create_workers_subclass(self):
        """Create workers using subclassing"""
        class WorkerThread(threading.Thread):
            def __init__(self, processor, worker_id):
                threading.Thread.__init__(self)
                self.processor = processor
                self.worker_id = worker_id
                self.name = f"Worker-{worker_id}"
            
            def run(self):
                self.processor.worker_function(self.worker_id)
        
        threads = []
        for i in range(self.num_workers):
            t = WorkerThread(self, i)
            threads.append(t)
            t.start()
        return threads
    
    def create_workers_pool(self):
        """Create workers using ThreadPoolExecutor"""
        executor = ThreadPoolExecutor(max_workers=self.num_workers)
        futures = []
        
        for i in range(self.num_workers):
            future = executor.submit(self.worker_function, i)
            futures.append(future)
        
        return executor, futures
    
    # ============================================================
    # MAIN APPLICATION
    # ============================================================
    
    def run(self, num_tasks=20, method="function"):
        """Run the data processor"""
        print("=" * 60)
        print(f"DATA PROCESSOR - Method: {method}")
        print("=" * 60)
        
        self.running = True
        self.results = []
        
        # Add tasks to queue
        for i in range(num_tasks):
            self.task_queue.put(f"Task-{i+1}")
        
        print(f"Added {num_tasks} tasks to queue")
        
        # Start workers based on method
        if method == "function":
            threads = self.create_workers_function_target()
        elif method == "subclass":
            threads = self.create_workers_subclass()
        elif method == "pool":
            executor, futures = self.create_workers_pool()
        else:
            print("Invalid method")
            return
        
        # Wait for tasks to complete
        self.task_queue.join()
        
        # Stop workers
        self.running = False
        
        if method == "pool":
            executor.shutdown()
        else:
            for t in threads:
                t.join()
        
        print(f"\nCompleted {len(self.results)} tasks")
        print("Results:")
        for result in self.results[:5]:
            print(f"  {result}")
        if len(self.results) > 5:
            print(f"  ... and {len(self.results)-5} more")

# ============================================================
# RUN THE APPLICATION
# ============================================================

processor = DataProcessor(num_workers=3)

# Test all three methods
processor.run(num_tasks=10, method="function")

print("\n" + "=" * 60)
print("METHOD COMPARISON SUMMARY")
print("=" * 60)

print("""
┌─────────────────────────────────────────────────────────────────┐
│ METHOD           │ BEST FOR                                   │
├─────────────────────────────────────────────────────────────────┤
│ Function Target  │ Simple, one-off tasks                      │
│ Subclassing      │ Complex threads with state                │
│ ThreadPool       │ Many small tasks, efficient               │
└─────────────────────────────────────────────────────────────────┘

Choose the method that best fits your needs!
""")

Real-world example key points:

  • Queue-based — tasks are queued and processed
  • Multiple methods — demonstrates all three approaches
  • Thread-safe — uses locks for shared data
  • Scalable — can handle many tasks

Quick Check: What is the advantage of using a queue with threads? (Answer: It provides thread-safe communication between threads)

Best Practices

8

Thread Creation Best Practices

# ============================================================
# THREAD CREATION BEST PRACTICES
# ============================================================

print("1. USE THE RIGHT METHOD")
print("   - Function target for simple tasks")
print("   - Subclassing for complex threads")
print("   - ThreadPoolExecutor for many tasks")

print("\n2. ALWAYS JOIN THREADS")
print("   - Ensure threads complete before program exits")
print("   - Prevents resource leaks")
print("   - Use try/finally for safety")

print("\n3. NAME YOUR THREADS")
print("   - Use meaningful names")
print("   - Makes debugging easier")
print("   - thread.name = 'Worker-1'")

print("\n4. USE DAEMON THREADS CAREFULLY")
print("   - Use for background tasks")
print("   - Don't use for critical work")
print("   - Set t.daemon = True before start")

print("\n5. HANDLE EXCEPTIONS")
print("   - Exceptions in threads don't propagate")
print("   - Use try/except inside thread functions")
print("   - Log errors for debugging")

print("\n6. USE QUEUES FOR COMMUNICATION")
print("   - from queue import Queue")
print("   - Thread-safe and easy to use")
print("   - Avoid shared variables without locks")

print("\n7. LIMIT THREAD COUNT")
print("   - Too many threads = performance issues")
print("   - Use ThreadPoolExecutor for limits")
print("   - Max workers = 2 * CPU cores for CPU tasks")

print("\n8. USE LOCKS FOR SHARED DATA")
print("   - from threading import Lock")
print("   - Lock before reading/writing shared data")
print("   - Unlock immediately after")

Best practices summary:

  • Choose right method — based on task complexity
  • Always join — prevent resource leaks
  • Name threads — easier debugging
  • Use queues — thread-safe communication

Quick Check: What should you use for thread-safe communication? (Answer: Queue)

Try It Yourself

Experiment with creating threads in the editor below.

Loading Pyodide... 0%
Python Code Editor
========================================
CREATING THREADS - PRACTICE
========================================

1. FUNCTION TARGET METHOD
----------------------------------------
Starting: Thread-1
Thread-1: Working...
Starting: Thread-2
Thread-2: Working...
Starting: Thread-3
Thread-3: Working...
Completed: Thread-3
Completed: Thread-1
Completed: Thread-2
Joined: Thread-1
Joined: Thread-2
Joined: Thread-3
Result 1: Thread-1 completed
Result 2: Thread-2 completed
Result 3: Thread-3 completed

2. SUBCLASSING METHOD
----------------------------------------
Starting: Worker-A
Worker-A: Running task 1
Starting: Worker-B
Worker-B: Running task 2
Completed: Worker-A
Completed: Worker-B
Joined: Worker-A
Joined: Worker-B
Result A: Task 1 done
Result B: Task 2 done

3. THREAD POOL METHOD
----------------------------------------
Pool task 0: Working...
Pool task 1: Working...
Pool task 2: Working...
Pool task 3: Working...
Pool task 4: Working...

4. THREAD CREATION SUMMARY
----------------------------------------
┌─────────────────────────────────────────────────────────────────┐
│ METHOD │ WHEN TO USE │
├─────────────────────────────────────────────────────────────────┤
│ Function Target │ Simple tasks, quick and easy │
│ Subclassing Thread │ Complex threads with state │
│ ThreadPoolExecutor │ Many small tasks, efficient │
└─────────────────────────────────────────────────────────────────┘

Three ways to create threads, choose the right one!
🏆

You've Got It!

You now know how to create threads in Python using three different methods. You understand when to use each method and the thread lifecycle.

Quick Quiz

Test what you've learned:

1. What is the simplest way to create a thread?
2. What method do you override when subclassing Thread?
3. Which method is best for many small tasks?
4. What state is a thread in when it's running?
5. What should you use for thread-safe communication?

Frequently Asked Questions

What is the difference between function target and subclassing Thread? ▼

Function target is simpler and more Pythonic. You pass a function to the Thread constructor. Subclassing Thread gives you more control and is better for complex threads that need to maintain state or have custom methods.

Why use ThreadPoolExecutor? ▼

ThreadPoolExecutor manages a pool of threads that can be reused for multiple tasks. It's efficient for many small tasks because it avoids the overhead of creating a new thread for each task. It also limits the number of concurrent threads.

What is a common interview question about creating threads? ▼

Common questions include: "How do you create a thread in Python?" "What are the different ways to create threads?" "What is the difference between threading and ThreadPoolExecutor?" and "When would you use subclassing over function target?"

Can a thread return a value? ▼

Threads don't return values directly. You can store results in a shared data structure (like a list) or use a queue. ThreadPoolExecutor's submit() returns a Future object that can retrieve the result using future.result().

What is the thread lifecycle? ▼

The thread lifecycle has four states: NEW (created), RUNNABLE (running or ready), BLOCKED (waiting for resource), and TERMINATED (finished). You can check the state using thread.is_alive().

Where to Go From Here

Now that you know how to create threads, check out these related topics:

Single Tasking

Learn about single-threaded execution.

Learn More →

Multi Tasking

Learn about concurrent execution.

Learn More →

Thread Synchronization

Learn how to safely share data between threads.

Learn More →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Uses of Threads Next: Single Tasking →