编辑:我正在尝试为 Web 应用程序的所有会话创建一个共享数据库连接池。另一篇帖子说,创建servlet上下文对象的最佳方法是让init侦听器创建它。但是,我不清楚如何使此对象可供我的servlet使用。
另一种方法是使用静态初始化:
public class SomeClass {
private static final Object[] CONTENT;
static {
CONTENT = new Object[SomeOtherClass.getContentSize()]; // To show you can access runtime variables
}
}
这将在使用类加载器加载类后初始化CONTENT
数组。
一种解决方案是使用私有持有者类:
public class SomeClass {
private static class ResourceHolder {
private static final Resource INSTANCE = new Resource();
}
public static Resource getInstance() {
return ResourceHolder.INSTANCE;
}
}
第一次调用SomeClass.getInstance()
时将初始化实例。
最简单的延迟初始化是将enum
与一个实例一起使用。
enum Singleton {
INSTANCE; // lazy initialised
}
增加的问题是您需要初始化值。 要处理这个问题,你可以嵌套类。
enum Utility {;
static MyType val;
static OtherType val2;
enum Holder {
INSTANCE;
Holder() {
// uses val and val2
}
}
public static Holder getInstance(MyType val, OtherType val2) {
Utility.val = val;
Utility.val2 = val2;
return Holder.INSTANCE; // only created the first time.
}
}
注意:这是线程安全的,因为静态块初始化是安全的。
像这样:
public static abstract class Lazy<T> {
private T t = null;
public synchronized T get() {
if (t == null) {
t = create();
}
return t;
}
protected abstract T create();
}
public static final Lazy<List<String>> lazyList = new Lazy<List<String>>(){
@Override
protected List<String> create() {
return new ArrayList<String>();
}
};
我会提前提醒你,你所描述的内容有一点代码气味,我怀疑你最好完全避免这种模式。 依赖于外部运行时状态的静态资源会破坏有关变量作用域的各种最佳做法。
但是,您所描述的内容最好由Supplier
或Future
实现,具体取决于成功构建所需对象所涉及的工作。 这种差异有些迂腐,但您通常会使用 Future
来保存需要很长时间才能计算的引用,而Supplier
通常会快速返回。 Future
也有一些很好的与Java的并发实用程序的挂钩,但从听起来你不需要它。
您可以使用如下Supplier
:
public class GlobalState {
public static final Supplier<LazyData> MY_DATA = Suppliers.memoize(
new Supplier<LazyData>() {
public LazyData get() {
// do whatever you need to construct your object, only gets executed once needed
}
});
...
}
Suppliers.memoize()
将以线程安全的方式缓存对基础Supplier
的第一次调用的结果,因此只需包装使用此调用定义的Supplier
即可防止重复处理。