使用Lock Object实现单例与经典双重检查锁单例的差异及锁对象作用解析
Great question! Let's break down the core differences between these two singleton implementations and unpack the thinking behind using a dedicated lock object.
1. Locking Behavior & Performance
Your implementation uses eager locking: every call to getEntryPoint() acquires the lock first, even after the entryPoint instance is already initialized. This means every subsequent call has to wait for the lock to be released, adding unnecessary overhead once the singleton is fully ready.
The classic double-checked locking (DCL) implementation is optimized for performance: it first checks if entryPoint is null without locking. Only if the instance doesn't exist does it enter the synchronized block. After initialization, all future calls skip the lock entirely, making it much faster for repeated access.
2. Lock Target Isolation
- Your code uses a dedicated
LOCK_OBJECTas the synchronization target. This lock is only used within this singleton initialization logic, keeping its scope tightly controlled. - The classic DCL uses
Service.classas the lock. Since the class object is a global resource, any other code in your application that also synchronizes onService.classwill compete for the same lock, potentially causing unexpected blocking and bottlenecks.
3. Initialization Safety Requirements
- In your implementation, every access is wrapped in a synchronized block, so you don't need to mark
entryPointasvolatile. The lock itself ensures all threads see the most up-to-date value ofentryPoint. - The classic DCL requires
entryPointto be markedvolatile(in Java 5+). Withoutvolatile, the JVM might reorder the initialization steps ofService, leading to threads seeing a partially initialized instance ofentryPoint.
Using a dedicated LOCK_OBJECT instead of the class object has three key benefits:
- Eliminate Cross-Code Lock Contention: As mentioned earlier, other parts of your codebase that use
Service.classfor synchronization won't interfere with your singleton's initialization logic. This isolates lock scopes and prevents unintended slowdowns. - Clearer Code Intent: A named lock object like
LOCK_OBJECTmakes it immediately obvious to other developers that this lock exists solely to protect the singleton's initialization. UsingService.classis more ambiguous—readers might wonder if the lock is used elsewhere in the class. - Future Flexibility: If you ever need to switch to a more advanced locking mechanism (like
java.util.concurrent.locks.ReentrantLock), having a dedicated object makes this refactor much easier. You won't have to untangle dependencies on the class object as a lock.
内容的提问来源于stack exchange,提问作者kamil.rak

