DCL(Double-checked Locking)是Lazy-loading时避免过度同步(多线程考虑)采用的技巧。下面是个例子:
class SomeClass {
private Resource resource = null;
public Resource getResource() {
if (resource == null) {
synchronized(this) {
if (resource == null)
resource = new Resource();
}
}
return resource;
}
}
这样做避免在getResource()方法上进行synchronized,而且调用getResource()不会每次都进行synchronized,提高了效率。但它真的解决了同步问题吗?没有!详细参见下面文章:
Warning! Threading in a multiprocessor world
Find out why many tricks to avoid synchronization overhead just don't work
www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html
Double-checked locking: Clever, but broken
www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
Can double-checked locking be fixed?
No matter how you rig it, double-checked locking still fails
www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html
The "Double-Checked Locking is Broken" Declaration
www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
有两种代替方法:
class SomeClass {
private Resource resource = null;
public synchronized static Resource getResource() {
if (resource == null) {
resource = new Resource();
}
return resource;
}
}
class SomeClass {
private static Resource resource = new Resource();
public static Resource getResource() {
return resource;
}
}
或者使用ThreadLocal加DCL的方法,但因为ThreadLocal本身的性能问题,采用时也要考虑。如果采用JDK 1.4.2以上,ThreadLocalDCL方式是比直接在方法上synchronized效率高而且安全的。
class ThreadLocalDCL {
private static ThreadLocal initHolder = new ThreadLocal();
private static Resource resource = null;
public Resource getResource() {
if (initHolder.get() == null) {
synchronized(this) {
if (resource == null)
resource = new Resource();
initHolder.set(Boolean.TRUE);
}
}
return resource;
}
}
详细请看下面文章:
Can ThreadLocal solve the double-checked locking problem?
ThreadLocal appears to fix the thread-safety issues behind double-checked locking
www.javaworld.com/javaworld/jw-11-2001/jw-1116-dcl.html
还有一种方式,是否解决问题:
public final class FooSingleton {
// 开始时不会被加载,直到调用getInstance()时才加载
private static final class SingletonHolder {
static final FooSingleton _singleton = new FooSingleton ();
}
private FooSingleton () {
}
public static FooSingleton getInstance () {
return SingletonHolder._singleton;
}
}
不过不知道是否适合一些属性是Lazy-loading的情况?
And how about this one?
public class Utopia {
private Foo instance = null;
public Foo getFoo() {
if (instance != null)
return instance;
// (this) is redundant, but included to emphasize that we're NOT sync'ing on instance.
synchronized<instance>(this) {
// at this point, we'll see the old value of 'instance' if no thread has changed it
// from inside this synchronized block, or its most recent value if some prior thread
// executing within this block has given it a new value.
if (instance == null)
instance = new Foo();
// we MUST do the return here, because instance's new value has not necessarily been
// propagated out to the "real" 'instance' variable visible to the outside world yet...
return instance;
}
// at some point in the future, the new value of instance will be atomically
// propagated to its namesake "out here"
}
}
关于这个问题,最终还是没有找到定论。但是,DCL是有隐患的,所以不用为妙。
class SomeClass {
private Resource resource = null;
public Resource getResource() {
if (resource == null) {
synchronized(this) {
if (resource == null)
resource = new Resource();
}
}
return resource;
}
}
这样做避免在getResource()方法上进行synchronized,而且调用getResource()不会每次都进行synchronized,提高了效率。但它真的解决了同步问题吗?没有!详细参见下面文章:
Warning! Threading in a multiprocessor world
Find out why many tricks to avoid synchronization overhead just don't work
www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html
Double-checked locking: Clever, but broken
www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
Can double-checked locking be fixed?
No matter how you rig it, double-checked locking still fails
www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html
The "Double-Checked Locking is Broken" Declaration
www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
有两种代替方法:
class SomeClass {
private Resource resource = null;
public synchronized static Resource getResource() {
if (resource == null) {
resource = new Resource();
}
return resource;
}
}
class SomeClass {
private static Resource resource = new Resource();
public static Resource getResource() {
return resource;
}
}
或者使用ThreadLocal加DCL的方法,但因为ThreadLocal本身的性能问题,采用时也要考虑。如果采用JDK 1.4.2以上,ThreadLocalDCL方式是比直接在方法上synchronized效率高而且安全的。
class ThreadLocalDCL {
private static ThreadLocal initHolder = new ThreadLocal();
private static Resource resource = null;
public Resource getResource() {
if (initHolder.get() == null) {
synchronized(this) {
if (resource == null)
resource = new Resource();
initHolder.set(Boolean.TRUE);
}
}
return resource;
}
}
详细请看下面文章:
Can ThreadLocal solve the double-checked locking problem?
ThreadLocal appears to fix the thread-safety issues behind double-checked locking
www.javaworld.com/javaworld/jw-11-2001/jw-1116-dcl.html
还有一种方式,是否解决问题:
public final class FooSingleton {
// 开始时不会被加载,直到调用getInstance()时才加载
private static final class SingletonHolder {
static final FooSingleton _singleton = new FooSingleton ();
}
private FooSingleton () {
}
public static FooSingleton getInstance () {
return SingletonHolder._singleton;
}
}
不过不知道是否适合一些属性是Lazy-loading的情况?
And how about this one?
public class Utopia {
private Foo instance = null;
public Foo getFoo() {
if (instance != null)
return instance;
// (this) is redundant, but included to emphasize that we're NOT sync'ing on instance.
synchronized<instance>(this) {
// at this point, we'll see the old value of 'instance' if no thread has changed it
// from inside this synchronized block, or its most recent value if some prior thread
// executing within this block has given it a new value.
if (instance == null)
instance = new Foo();
// we MUST do the return here, because instance's new value has not necessarily been
// propagated out to the "real" 'instance' variable visible to the outside world yet...
return instance;
}
// at some point in the future, the new value of instance will be atomically
// propagated to its namesake "out here"
}
}
关于这个问题,最终还是没有找到定论。但是,DCL是有隐患的,所以不用为妙。
回复Comments
作者:
{commentrecontent}