Is this a safe version of double-checked locking?
Here's an idea I just came up with for a safe, efficient way of handling Singleton synchronization issues. It's basically double-checked locking, but with a twist that involves thread-local storage. In Java/C#/D-style pseudocode, assuming __thread
denotes thread-local storage for static vari开发者_Python百科ables:
class MySingleton {
__thread static bool isInitialized;
static MySingleton instance;
static MySingleton getInstance() {
if(!isInitialized) {
synchronized {
isInitialized = true;
if(instance is null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
This is guaranteed to only enter the synchronized
block once per thread throughout the entire life of the program. From that point forward, we get a simple check of a thread-local bool to see whether we've already entered the synchronized block and verified that the object is initialized from this thread.
I do not think a language-agnostic (or platform-agnostic) approach is helpful here, because while the construct may be logically sound, there are implementation-specific gotchas that will prevent it from working properly. An example is the double-checked locking that just did not work on Java pre-5 because it was broken at the JVM level.
So you should be using the available language constructs or libraries on each platform.
For Java, you can get singletons using enum
.
This appears clean. The actual check and initialization of your instance object is inside a synchronized block and each thread is forced to enter the synchronized block on the first call, you get a clean happens-before edge between threads.
Since isInitialized is thread-local, why are you setting it inside the synchronized block? Also, you should only set isInitalized after constructing your singleton object. This way, if it hasn't been initialized yet and the constructor throws, this thread will check again the next time it's called.
if(!isInitialized) {
synchronized {
if(instance is null) {
instance = new MySingleton();
}
}
isInitialized = true;
}
The reason double-checked locking is broken (to the best of my knowledge) is the possibility that instance
is not null but also not fully constructed due to read/write reordering.
Thread-local storage wouldn't solve anything. It might get you around from having to declare isInitialized
as volatile, but that still doesn't fix your problem.
Yes, this construct is safe under all the high level languages that I know of. In particular, it is safe in any language where the memory/concurrency models guarantee that a given thread always sees it's own operations in an order consistent with program order (which is pretty much any useful language), and where the synchronized block or equivalent provides the usual guarantees with respect to operations before, within and after the block.
Looks good to me as far as Java is concerned. If you are going to do it this way, it is more conventional to make the thread-local storage a reference. No point in reading the static as well.
But in Java class loading is lazy and thread-safe, so you might as well just write:
private static final MySingleton instance = new MySingleton();
Or not use singletons at all.
Yes, under new jdk5 JMM if you declare instance volatile DCL will work
精彩评论