我需要在并发环境中延迟加载资源.加载资源的代码只能执行一次.
这两个双重检查锁定(使用JRE 5+和volatile关键字)和初始化按需持有者成语似乎适合这个职业.
仅仅通过查看代码,按需初始化持有者习惯看起来更干净,更有效(但是嘿,我猜这里).不过,我必须小心并记录我的每一个单身人士的模式.至少在我看来,很难理解为什么代码会在现场写出来......
我的问题是:哪种方法更好?为什么?如果你的答案是否定的.您将如何在Java SE环境中解决此要求?
备择方案
我可以使用CDI而不强制它在整个项目中使用吗?那里有文章吗?
创建单身人士的模式似乎是这样的:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance()
{
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我的问题是如果Singleton构造函数执行非单元测试友好的事情,例如调用外部服务,jndi查找等,你如何使用这样的类.
我想我可以重构它:
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public synchronized static Singleton getInstance()
{
if(instance == null)
instance = new Singleton();
return instance;
}
//for the unit tests
public static void setInstance(Singleton s)
{
instancce = s;
}
}
Run Code Online (Sandbox Code Playgroud)
现在的问题是,仅仅为了单元可测试性,我已经强制getInstance被同步,因此只是对于测试方面,它将对实际应用程序产生负面影响.有没有办法解决它,似乎任何其他类型的延迟初始化将无法工作,因为java中双锁模式的破坏性质.
我看到了这样的答案,试图通过评论来澄清,但对这里的例子不满意。
也许是时候提出这个具体问题了......
为什么枚举单例实现被称为惰性?
public enum EnumLazySingleton {
INSTANCE;
EnumLazySingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
Run Code Online (Sandbox Code Playgroud)
它与急切的实现有何不同?
public class BasicEagerSingleton {
private static final BasicEagerSingleton instance = new BasicEagerSingleton();
public static BasicEagerSingleton getInstance() {
return instance;
}
private BasicEagerSingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
Run Code Online (Sandbox Code Playgroud)
两者都将初始化实例而不访问INSTANCE/getInstance()- 例如 call touchClass()。
public class TestSingleton {
public static void main(String... args) …Run Code Online (Sandbox Code Playgroud) java singleton enums double-checked-locking lazy-initialization