What does synchronized do as a singleton method in objective C?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Objective-C singleton code, @synchronized provides mutual exclusion so only one thread executes a protected block at a time. It can make lazy singleton initialization thread-safe, but it is not the preferred modern pattern for one-time instance creation. To use it correctly, you need to understand lock scope, lock object choice, and alternatives such as dispatch_once.
What @synchronized Actually Does
@synchronized(lockObject) acquires a runtime lock associated with lockObject, executes the block, then releases the lock even if an exception occurs.
In this pattern, locking prevents two threads from creating two instances simultaneously.
Why dispatch_once Is Usually Better
For singleton initialization, dispatch_once is designed specifically for exactly-once execution and typically has lower post-init overhead.
This is the common recommendation for singleton creation in modern Objective-C code.
Lock Scope Matters
Even when @synchronized is correct, lock scope should stay minimal. Long operations inside the lock increase contention and startup latency.
Avoid this pattern:
- Lock acquired.
- Disk I/O and heavy parsing inside lock.
- Network initialization inside lock.
- Lock released.
Prefer creating the instance quickly under lock and moving expensive setup elsewhere.
Choosing the Lock Object Consistently
In class methods, @synchronized(self) locks on class object. That is valid, but consistency is critical. If one code path uses class object and another uses instance object for related state, synchronization guarantees break.
For non-singleton critical sections, a private lock object often improves clarity.
Then use @synchronized(self.lock) for that specific state.
Migration from @synchronized to dispatch_once
Many legacy projects still use synchronized singleton accessors. Migration is typically straightforward:
- Keep API method unchanged.
- Replace synchronized block with
dispatch_once. - Run concurrent access tests.
- Verify no hidden side effects depend on repeated initialization.
This improves readability and aligns with current platform conventions.
Concurrency Testing Pattern
A practical test is to fetch singleton from many concurrent queues and assert all references are identical.
Then validate that every stored pointer equals the first one.
@synchronized Beyond Singletons
@synchronized still has valid uses for protecting mutable shared state. But for high-contention systems, lower-level locking primitives can offer better performance. Use @synchronized when clarity matters more than micro-optimization and contention is moderate.
Common Pitfalls
- Using
@synchronizedfor singleton creation whendispatch_onceis more direct. - Locking large expensive code blocks and creating unnecessary contention.
- Mixing lock objects for the same shared state.
- Hiding side effects in singleton accessor methods.
- Skipping concurrency tests after changing initialization logic.
Summary
- '
@synchronizedprovides mutual exclusion around Objective-C critical sections.' - It can make singleton lazy initialization safe but is not the best modern singleton primitive.
- '
dispatch_onceis preferred for exactly-once singleton creation.' - Keep lock scope small and lock object strategy consistent.
- Validate thread safety with explicit concurrent access tests.

