Python Threads – Create and Manage Threads with Examples

Introduction

Python provides Threads to achieve concurrent execution within a single process. Threads allow a program to perform multiple operations simultaneously without creating separate processes.

The Python threading module makes it easy to create, manage, and synchronize threads. Threads are commonly used for:

  • File downloads
  • Network requests
  • Background tasks
  • Data processing
  • GUI applications
  • Real-time systems

In this article, you’ll learn what Python Threads are, how they work, their syntax, practical examples, real-life use cases, common mistakes, interview questions, and best practices.

What are Python Threads?

A Thread is the smallest unit of execution within a process.

A process can contain multiple threads, and these threads share the same memory space.

Without threading:


Task 1 → Complete
Task 2 → Complete
Task 3 → Complete

With threading:


Task 1 
Task 2
Task 3
Running Concurrently

Threads help improve responsiveness and resource utilization.

Why Use Threads?

Threads provide several advantages:

1. Concurrent Execution

Perform multiple tasks simultaneously.

2. Better User Experience

Applications remain responsive during long-running operations.

3. Resource Sharing

Threads share memory within a process.

4. Faster I/O Operations

Ideal for file handling and network communication.

5. Background Processing

Execute tasks without blocking the main program.

Thread vs Process

Feature Thread Process
Memory Shared Separate
Speed Faster Slower
Creation Cost Low High
Communication Easy Complex
Resource Usage Less More

Python Threading Module

Python provides the built-in threading module for thread management.

Import the module:


import threading

Creating a Thread

Syntax


thread = threading.Thread(
    target=function_name
)

Start the thread:


thread.start()

Example: Creating a Simple Thread


import threading
def display():
   print("Thread Running")
thread = threading.Thread(
    target=display
)
thread.start()

Output:

Thread Running

Main Thread

Every Python program starts with a main thread.

Example:


import threading
print(
    threading.current_thread()
)

Output:

<_MainThread(MainThread)>

Creating Multiple Threads

Example:


import threading
def task():
    print("Task Executed")
thread1 = threading.Thread(
    target=task
)
thread2 = threading.Thread(
    target=task
)
thread1.start()
thread2.start()

Output:

Task Executed
Task Executed

Passing Arguments to Threads

Example:


import threading
def greet(name):
    print(
        f"Hello {name}"
    )
thread = threading.Thread(
    target=greet,
    args=("John",)
)
thread.start()

Output:

Hello John

Using join()

The join() method waits for a thread to complete.

Example:


import threading
import time
def task():
    time.sleep("2")
    print("Task Finished")
thread = threading.Thread(
    target=task
)
thread.start()
thread.join()
print("Program Ended")

Output:

Task Finished
Program Ended

Without join(), the main program may continue execution immediately.

Naming Threads

Example:


import threading
def task():
    print(
        threading.current_thread().name
    )
thread = threading.Thread(
    target=task,
    name="WorkerThread"
)
thread.start()

Output:

WorkerThread

Thread Class Inheritance

Another way to create threads is by extending the Thread class.

Example:


import threading
class MyThread(
    threading.Thread
):
    def run(self):
        print(
            "Custom Thread Running"
        )
thread = MyThread()
thread.start()

Output:

Custom Thread Running

Daemon Threads

Daemon threads run in the background.

Example:


import threading
def background_task():
    while True:
        pass
thread = threading.Thread(
    target=background_task,
    daemon=True
)
thread.start()

Daemon threads automatically stop when the main program exits.

Thread Synchronization

When multiple threads access shared resources, problems may occur.

Example:


balance = 1000

Two threads modifying the same variable simultaneously may produce incorrect results.

Synchronization helps prevent such issues.

Lock Object

A lock ensures only one thread accesses a resource at a time.

Example:


import threading
lock = threading.Lock()
def task():
    with lock:
        print(
            "Resource Accessed"
        )

Output:

Resource Accessed

Example: Using Lock


import threading
counter = 0
lock = threading.Lock()
def increment():
    global counter
    for i in range(1000):
        with lock:
            counter += 1
thread1 = threading.Thread(
    target=increment
)
thread2 = threading.Thread(
    target=increment
)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(counter)

Output:

2000

Without a lock, the result may be inconsistent.

Thread Lifecycle

A thread goes through several states:


New
 ↓
Runnable
 ↓
Running
 ↓
Blocked/Waiting
 ↓
Terminated

Understanding the lifecycle helps in debugging multithreaded applications.

Real-Life Example: Download Manager

Imagine downloading multiple files.

Without threads:


File1 Download
File2 Download
File3 Download

With threads:


File1 Downloading
File2 Downloading
File3 Downloading

All downloads run concurrently.

Real-Life Example: Web Scraping


import threading
def scrape(url):
    print(
        f"Scraping {url}"
    )
urls = [
    "site1.com",
    "site2.com",
    "site3.com"
]
for url in urls:
    thread = threading.Thread(
        target=scrape,
        args=(url,)
    )
    thread.start()

This speeds up data collection.

Common Thread Methods

Method Description
start() Starts thread execution
join() Waits for completion
is_alive() Checks thread status
current_thread() Returns current thread
getName() Gets thread name
setName() Sets thread name

Advantages of Python Threads

Advantage Description
Faster I/O Operations Improves responsiveness
Shared Memory Easy communication
Lightweight Uses fewer resources
Better User Experience Prevents application freezing
Background Execution Runs tasks independently

Common Mistakes

1. Forgetting start()

Incorrect:


thread = threading.Thread(
    target=task
)

The thread never runs.

Correct:


thread.start()

2. Not Using join()

The main program may finish before threads complete.

Use:


thread.join()

3. Ignoring Locks

Multiple threads modifying shared data can cause race conditions.

Use:


threading.Lock()

4. Creating Too Many Threads

Excessive threads can reduce performance.

Use thread pools for large applications.

5. Using Threads for CPU-Intensive Tasks

Threads are not ideal for heavy CPU computations due to GIL.

Use multiprocessing instead.

Conclusion

Python Threads provide an effective way to execute multiple tasks concurrently within a single process. Using the threading module, developers can create threads, pass arguments, synchronize resources, and build responsive applications.

Threads are particularly useful for I/O-bound operations such as file handling, web scraping, downloads, and background processing.

Related Python Tutorials