Java线程安全实现懒初始化两个方式

Java中以线程安全方式实现懒初始化对象有很多写法,这里不讨论针对全局单例场景,而是讨论缓存的使用场景,通常为了提高性能,我们经常通过key/对象形式将对象保存到内存中,具体来说,首先我们需要检查缓存中或application作用域中是否有存在对应某个key的对象,如果不存在我们new一个对象实例放进去,这个过程是懒初始化过程,多线程环境为防止并发同时初始化对象实例 ,大概有两种方式:

使用同步方式:
来自:http://www.codeproject.com/Articles/418425/Demystifying-concurrent-lazy-load-pattern


public IList<Product> GetProducts()
{
// declare local variable for cache access
// and use it to be safe on sudden cache resetting
List<Product> result = this.localCache;
if (result == null)
{
lock (this.syncLock)
{
// recheck condition after acquiring lock
// to be sure cache is not loaded while waiting for the lock
result = this.localCache;
if (result == null)
{
// it is important to first store result in local variable
// and only after in cache because in between cache
// might be reset
result = this.LoadProductsFromDatabase();
this.localCache = result;
}
}
}

// important – return local variable and not this.localCache
// above code guaranties that result will have value
// on the other hand this.localCache might be reset at any time
return result;
}

public void Reset()
{
// no need for any kind of locking
// because our lazy load can handle resetting at any time
this.localCache = null;
}

非同步的方式:
来自:http://timezra.blogspot.com/2008/04/threadsafe-lazy-instantiation-without.html


class ThreadsafeLazyGetter extends LazyGetter {
private final AtomicReference<Object> lazilyCreatedObject =
new AtomicReference<Object>();

@Override
Object get() {
final Object existingValue = lazilyCreatedObject.get();
if (existingValue != null) {
return existingValue;
}
final Object newValue = performLongRunningInitialization();
if (lazilyCreatedObject.compareAndSet(null, newValue)) {
return newValue;
}
return lazilyCreatedObject.get();
}
}

点评:虽然非同步方式从理论上看没有锁,应该比同步方式快,但是代码不是很直接,相当于加了个套子AtomicReference,这两者还是各有其使用场景的。

Java 8引入了Lambda,见:用Java 8实现懒初始化,有些类似上面非同步方式,代码比较重量,关键是Java不是将函数作为第一等公民导致,看看Javascript中实现:


var tasksPromise;
function getTasks() {
taskPromise = taskPromise || getTasksFromTheServer();
return taskPromise;
}

上述代码中getTasksFromTheServer只会执行一次。来自:NodeJS的Promise的用法

[该贴被banq于2015-01-30 21:40修改过]