Home » Python Joining Threads Tutorial with Examples

Python Joining Threads Tutorial with Examples

Java SE 11 Programmer I [1Z0-815] Practice Tests
Java SE 11 Developer (Upgrade) [1Z0-817]
1 Year Subscription
Spring Framework Basics Video Course
Java SE 11 Programmer II [1Z0-816] Practice Tests
Oracle Java Certification

In Python, when working with multiple threads, you may want the main thread (or other threads) to wait for some threads to complete before proceeding.

This is where the join() method comes in. Joining threads ensures that the main thread waits for the completion of the thread that has been joined, making thread synchronization easier.

In this tutorial, we will cover:

  1. What is Thread Joining in Python?
  2. Basic Usage of join() Method
  3. Using join() to Wait for a Single Thread
  4. Using join() to Wait for Multiple Threads
  5. Setting a Timeout with join()
  6. Daemon Threads and Joining
  7. Examples and Use Cases

Let’s dive into each topic with examples!

1. What is Thread Joining in Python?

When you start multiple threads in Python, they run concurrently with the main thread.

The main thread continues executing without waiting for the threads to complete.

However, there are situations where you may want the main thread to wait for a thread or multiple threads to finish their tasks before proceeding. This is done using the join() method.

  • join() makes the main program (or other threads) wait until the thread that called join() has finished its execution.
  • Without join(), the main thread may finish its execution while other threads are still running.

2. Basic Usage of join() Method

The basic syntax of join() is:

thread.join()

This tells the current thread to wait for the thread that calls join() to finish its task.

3. Using join() to Wait for a Single Thread

Let’s start by joining a single thread, ensuring that the main thread waits for the completion of a thread before continuing execution.

Example 1: Joining a Single Thread

import threading
import time

def task():
    print("Thread task started.")
    time.sleep(2)
    print("Thread task completed.")

# Create and start a thread
thread = threading.Thread(target=task)
thread.start()

# Wait for the thread to complete using join()
print("Waiting for thread to finish...")
thread.join()  # Main thread waits for this thread to complete
print("Main thread continues after the thread has finished.")

Explanation:

  • The thread runs the task() function, which takes 2 seconds to complete.
  • The main thread waits for the thread.join() call to finish.
  • The main thread prints “Main thread continues…” only after the thread completes.

4. Using join() to Wait for Multiple Threads

If you have multiple threads running concurrently, you can use join() to make the main thread wait for each thread to finish. You call join() on each thread separately.

Example 2: Joining Multiple Threads

import threading
import time

def task(name, seconds):
    print(f"Thread {name} started.")
    time.sleep(seconds)
    print(f"Thread {name} completed.")

# Create multiple threads
thread1 = threading.Thread(target=task, args=("A", 2))
thread2 = threading.Thread(target=task, args=("B", 3))
thread3 = threading.Thread(target=task, args=("C", 1))

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

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

print("All threads have completed. Main thread continues.")

Explanation:

  • Three threads are created, each running the task() function with different sleep times (2, 3, and 1 seconds).
  • The main thread waits for all threads to finish using join() on each thread.
  • Only after all threads complete does the main thread print the final message.

5. Setting a Timeout with join()

You can provide a timeout to the join() method, which allows the main thread to wait only for a specified amount of time. If the thread finishes within the timeout, the main thread continues. If the thread does not finish within the timeout, the main thread proceeds without waiting for it.

Example 3: Using join() with a Timeout

import threading
import time

def long_task():
    print("Long task started.")
    time.sleep(5)
    print("Long task completed.")

# Create and start the thread
thread = threading.Thread(target=long_task)
thread.start()

# Wait for a maximum of 2 seconds for the thread to finish
print("Waiting for 2 seconds...")
thread.join(timeout=2)
print("Main thread continues after waiting for 2 seconds.")

Explanation:

  • The long_task() function takes 5 seconds to complete.
  • The thread.join(timeout=2) makes the main thread wait only 2 seconds.
  • After 2 seconds, the main thread continues executing, even though the thread is still running.

6. Daemon Threads and Joining

Daemon threads run in the background and automatically terminate when the main program exits, regardless of whether they have completed their task or not. You can combine daemon threads with the join() method, but the join will only wait as long as the main thread is running.

Example 4: Joining a Daemon Thread

import threading
import time

def background_task():
    while True:
        print("Daemon thread running...")
        time.sleep(1)

# Create and start a daemon thread
daemon_thread = threading.Thread(target=background_task)
daemon_thread.daemon = True
daemon_thread.start()

# Wait for 3 seconds and then continue
time.sleep(3)
print("Main thread finished. Daemon thread will stop.")

Explanation:

  • The background_task() runs indefinitely as a daemon thread.
  • The main thread sleeps for 3 seconds and then exits.
  • Since the daemon thread is set to daemon=True, it will be terminated as soon as the main thread finishes, without waiting for the background task to complete.

Example 5: Joining a Daemon Thread with Timeout

import threading
import time

def background_task():
    for i in range(5):
        print("Daemon thread working...")
        time.sleep(1)

# Create and start a daemon thread
daemon_thread = threading.Thread(target=background_task)
daemon_thread.daemon = True
daemon_thread.start()

# Try joining the daemon thread with a timeout
daemon_thread.join(timeout=2)
print("Main thread continues after waiting 2 seconds for the daemon thread.")

Explanation:

  • The daemon thread runs for 5 seconds, but the join() call with a timeout of 2 seconds ensures the main thread only waits for 2 seconds.
  • After the timeout, the main thread continues, and the daemon thread continues running in the background until it completes its task or the main thread exits.

7. Examples and Use Cases

Example 6: Waiting for Threads with join()

In practical use cases, you may want to ensure that some critical tasks are finished before the main program terminates. Here’s an example of waiting for all threads in a download manager to finish:

import threading
import time

def download_file(file_name):
    print(f"Downloading {file_name} started.")
    time.sleep(3)
    print(f"Downloading {file_name} completed.")

# List of files to download
files = ["file1.txt", "file2.txt", "file3.txt"]

# Create and start threads for downloading files
threads = []
for file in files:
    thread = threading.Thread(target=download_file, args=(file,))
    threads.append(thread)
    thread.start()

# Wait for all downloads to complete
for thread in threads:
    thread.join()

print("All files downloaded. Main thread continues.")

Explanation:

  • Each file is downloaded in a separate thread.
  • The join() method ensures that the main thread waits for all downloads to finish before continuing.

Example 7: Checking if a Thread is Alive

You can check if a thread is still running using the is_alive() method, which is useful when combined with join().

import threading
import time

def task():
    print("Task started.")
    time.sleep(2)
    print("Task completed.")

# Create and start a thread
thread = threading.Thread(target=task)
thread.start()

# Check if the thread is alive
print(f"Is thread alive? {thread.is_alive()}")

# Wait for the thread to complete
thread.join()

# Check again if the thread is alive
print(f"Is thread alive? {thread.is_alive()}")

Explanation:

  • The is_alive() method returns True if the thread is still running, and False once the thread finishes its task.

Summary of Key Concepts for Joining Threads

Concept Description
thread.join() Waits for a thread to finish its execution.
thread.join(timeout) Waits for a specified amount of time for the thread to finish. If the thread doesn’t finish, it continues.
thread.is_alive() Checks whether a thread is still running.
Daemon Threads Daemon threads run in the background and are terminated when the main program exits.

Conclusion

In Python, the join() method is essential for synchronizing threads and ensuring the main program waits for threads to complete their tasks. In this tutorial, we covered:

  • Basic usage of the join() method to wait for a single thread.
  • Joining multiple threads and waiting for all of them to finish.
  • Setting a timeout with join() to limit how long the main thread waits for a thread.
  • Using join() with daemon threads to manage background tasks.
  • Practical examples, such as downloading files concurrently and checking if a thread is alive.

You may also like

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More