How do concurrency models like locks, async programming, and message passing differ in handling shared state?
Updated Feb 20, 2026
Short answer
Concurrency can be handled using shared-memory locking, asynchronous programming, or message passing, each with different approaches to managing shared state and coordination.
Deep explanation
Modern systems use different concurrency models depending on complexity, scalability, and safety requirements.
1\. Lock-based concurrency (shared memory model)
Threads share memory and use locks (mutexes, semaphores) to protect critical sections.
- Pros: Simple conceptually, widely used
- Cons: Risk of deadlocks, race conditions, contention
2\. Asynchronous programming (non-blocking model)
Tasks are executed without blocking threads, often using event loops or async/await patterns.
- Pros: High scalability, efficient I/O handling
- Cons: Harder debugging, complex flow control
3\. Message passing (actor model)
Instead of sharing memory, components communicate by sending messages. Each actor processes messages sequentially.
- Pros: No shared state → fewer race conditions
- Cons: Message overhead, design complexity
In large-scale distributed systems, message passing is often preferred (e.g., microservices), while async programming dominates I/O-heavy applications, and locks are still common in low-level or performance-critical systems.
Real-world example
- Lock-based: Multi-threaded banking system updating account balance
- Async: Web server handling thousands of HTTP requests
- Message passing: Microservices communicating via event queues
Common mistakes
- - Using locks where async would scale better.
- - Assuming async removes concurrency problems entirely.
- - Mixing shared memory and message passing without clear boundaries.
Follow-up questions
- When should you choose async over threads?
- What is the actor model?
- How do microservices handle concurrency safely?