You're building a bank account system. Multiple threads need to deposit and withdraw money. The balance must never go negative and updates must be atomic.
You could expose the balance field and have each caller acquire locks before accessing it. But now every piece of code that touches an account must remember to lock correctly. Miss a lock somewhere, and you have a race condition. Forget to release it, and you have a deadlock.
The Monitor Object Pattern solves this by encapsulating synchronization within the object itself. The account object owns its lock and all operations automatically synchronize. Callers just call deposit() or withdraw(). They don't know or care about locks. The object guarantees thread safety internally.
In this article, we'll explore:
If you're enjoying this newsletter and want to get even more value, consider becoming a [paid subscriber](https://blog.algomaster.io/subscribe).
As a paid subscriber, you'll unlock all premium articles and gain full access to all [premium courses](https://algomaster.io/newsletter/paid/resources) on [algomaster.io](https://algomaster.io).
The Monitor Object Pattern is a synchronization pattern where an object encapsulates both its data and the synchronization needed to access that data safely. All public methods that access shared state are automatically synchronized. The object acts as its own guardian.
The key insight is that synchronization is the object's responsibility, not the caller's. Callers interact with a clean interface without worrying about concurrency.
Without the Monitor Object Pattern, synchronization becomes the caller's burden.
Every caller must:
Problem 1: Forgotten Locks
Problem 2: Wrong Lock
Problem 3: Lock Leaks
Problem 4: Inconsistent Operations
The monitor encapsulates synchronization. Callers never touch locks.
Callers just call methods. The monitor handles all locking internally.
A monitor object has three components:
When a thread calls a synchronized method:
Only one thread executes inside the monitor at any time. Others wait at the door.
Let's build a thread-safe bank account using the Monitor Object Pattern.
The synchronized keyword makes each method acquire the object's intrinsic lock before executing.
Callers don't manage locks. The account handles everything.
For more control, use explicit locks instead of the synchronized keyword.
The try-finally pattern ensures the lock is always released.
Sometimes a thread needs to wait for a condition before proceeding. The Monitor Object Pattern supports this through condition variables.
This wastes CPU cycles and holds the lock, preventing deposits.
When a thread calls wait():
while Instead of if?Spurious wakeups can occur. The thread may wake up even when the condition isn't met. Always recheck in a loop.
Complex monitors often need multiple conditions. A thread might wait for different reasons.
A buffer that blocks when full (for producers) and when empty (for consumers).
Using separate conditions is more efficient. notFull.signal() only wakes producers, not consumers.
Use Monitor Object when:
Use External Locking when:
This can cause deadlocks. The callback might try to acquire another lock that's waiting for this one.
Solution: Release the lock before calling external code, or design to avoid such callbacks.
Use notifyAll() unless you're certain only one thread should proceed.
Always use a while loop. Conditions may not hold after waking up.
Go uses channels more than monitors, but you can build one:
The Monitor Object Pattern appears in many interview scenarios:
The Monitor Object Pattern encapsulates synchronization within an object, making thread safety the object's responsibility rather than the caller's.
The Monitor Object Pattern is fundamental to concurrent object-oriented design. It combines data encapsulation with synchronization, making it easier to write correct concurrent code.
Thank you for reading!
If you found it valuable, hit a like and consider subscribing for more such content every week.
If you have any questions or suggestions, leave a comment.
This post is public so feel free to share it.
P.S. If you're enjoying this newsletter and want to get even more value, consider becoming a [paid subscriber](https://blog.algomaster.io/subscribe).
As a paid subscriber, you'll unlock all premium articles and gain full access to all [premium courses](https://algomaster.io/newsletter/paid/resources) on [algomaster.io](https://algomaster.io).
There are [group discounts](https://blog.algomaster.io/subscribe?group=true), [gift options](https://blog.algomaster.io/subscribe?gift=true), and [referral bonuses](https://blog.algomaster.io/leaderboard) available.
Checkout my [Youtube channel](https://www.youtube.com/@ashishps_1/videos) for more in-depth content.
Follow me on [LinkedIn](https://www.linkedin.com/in/ashishps1/) and [X](https://twitter.com/ashishps_1) to stay updated.
Checkout my [GitHub repositories](https://github.com/ashishps1) for free interview preparation resources.
I hope you have a lovely day!
See you soon, Ashish