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.
Python code
18 linesimport 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
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
- Use `threading.RLock` if the same thread needs to acquire the lock multiple times (e.g., recursive calls).
- 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
More from Concurrency & performance
- Benchmark list.append vs deque.append in Python medium
- Build a Python Performance Profiler That Generates Readable Reports medium
- Graceful Shutdown Executor Context Manager in Python medium
- How to Build a Producer-Consumer Pattern with asyncio.Queue in Python medium
- How to Cancel an asyncio Task with Graceful Cleanup in Python medium
- How to Convert Data in Parallel with ThreadPoolExecutor in Python easy
Keep learning
Related tutorials and quizzes for this topic.