编辑:我正在尝试为 Web 应用程序的所有会话创建一个共享数据库连接池。另一篇文章说创建 servlet 上下文对象的最佳方法是让 init 侦听器创建它。然而,我不清楚如何使这个对象可供我的 servlet 使用。
5 回答
One solution is using a private holder class:
public class SomeClass {
private static class ResourceHolder {
private static final Resource INSTANCE = new Resource();
}
public static Resource getInstance() {
return ResourceHolder.INSTANCE;
}
}
the instance will be initialized when SomeClass.getInstance()
is called the first time.
另一种方法是使用静态初始化:
public class SomeClass {
private static final Object[] CONTENT;
static {
CONTENT = new Object[SomeOtherClass.getContentSize()]; // To show you can access runtime variables
}
}
CONTENT
一旦使用 ClassLoader 加载类,这将初始化数组。
最简单的延迟初始化是使用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>();
}
};
我会提前警告您,您所描述的内容有一点代码味道,我怀疑您最好完全避免这种模式。依赖于外部运行时状态的静态资源破坏了关于变量范围的各种最佳实践。
但是,您所描述的最好由 aSupplier
或 a实现Future
,具体取决于成功构建所需对象所涉及的工作。区别有点迂腐,但您通常会使用 aFuture
来保存需要很长时间来计算的引用,而 aSupplier
通常会快速返回。 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
您定义的内容即可防止重复处理。