How to Use threading.Lock to Synchronize a Counter in Python

Safely increment a shared counter across multiple threads using threading.Lock as a mutex to prevent race conditions.

Easy Python 3.9+ Aug 9, 2026 Concurrency & performance 14 views 0 copies

Python code

18 lines
Python 3.9+
import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(5)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print(f"Final counter value: {counter}")

Output

stdout
Final counter value: 500000

How it works

This code uses threading.Lock as a mutex to protect the counter += 1 operation. Without the lock, multiple threads could read the same value simultaneously and write back stale results, leading to a final value less than 500000. The with lock: statement acquires the lock before the increment and releases it automatically after, ensuring atomicity. Each of the 5 threads increments the counter 100,000 times, so the correct final value is 500,000. The main thread joins all threads to wait for completion before printing.

Common mistakes

  • Forgetting to use `global counter` inside the function, causing a local variable error instead of modifying the shared counter.
  • Creating a new `Lock` inside each thread, which makes the lock useless because threads do not share it.
  • Placing `lock.acquire()` and `lock.release()` manually without using `with` can leave the lock locked if an exception occurs.
  • Assuming the counter would be 500000 even without the lock; race conditions can make it lower and non-deterministic.

Variations

  1. Use `threading.RLock` if the same thread needs to acquire the lock multiple times (e.g., recursive calls).
  2. Use `queue.Queue` or `concurrent.futures.ThreadPoolExecutor` to avoid manual locks for simple task distribution.

Real-world use cases

  • Updating a shared database connection pool counter across concurrent web requests to track usage.
  • Incrementing a global metrics counter in a multithreaded server to record request counts without losing data.
  • Maintaining a progress counter in a multithreaded downloader that updates the UI thread safely.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Concurrency & performance

Related tutorials and quizzes for this topic.