我有一个类(RInterfaceHL)调用另一个类(JRIEngine),它在单线程应用程序上提供本机方法。因此,我只希望每个JVM都有一个类的实例(RInterfaceHL)。
我可以使用带有静态初始化的单例模式来确保只有RInterfaceHL的单个实例化,但是RInterfaceHL需要构造一个JRIEngine实例并为其提供一个loopback参数。如何以线程安全的方式提供单个RInterfaceHL实例,该实例接受用于构造单个JRIEngine的loopback参数?我正在使用JDK6。
注意:This同名的问题没有回答我的问题。
答案 0 :(得分:6)
修改使用Bill Pugh's initialization on demand holder idiom的单例模式。这是线程安全的,没有专门的语言结构(即volatile或synchronized)的开销:
public final class RInterfaceHL {
/**
* Private constructor prevents instantiation from other classes.
*/
private RInterfaceHL() { }
/**
* R REPL (read-evaluate-parse loop) handler.
*/
private static RMainLoopCallbacks rloopHandler = null;
/**
* SingletonHolder is loaded, and the static initializer executed,
* on the first execution of Singleton.getInstance() or the first
* access to SingletonHolder.INSTANCE, not before.
*/
private static final class SingletonHolder {
/**
* Singleton instance, with static initializer.
*/
private static final RInterfaceHL INSTANCE = initRInterfaceHL();
/**
* Initialize RInterfaceHL singleton instance using rLoopHandler from
* outer class.
*
* @return RInterfaceHL instance
*/
private static RInterfaceHL initRInterfaceHL() {
try {
return new RInterfaceHL(rloopHandler);
} catch (REngineException e) {
// a static initializer cannot throw exceptions
// but it can throw an ExceptionInInitializerError
throw new ExceptionInInitializerError(e);
}
}
/**
* Prevent instantiation.
*/
private SingletonHolder() {
}
/**
* Get singleton RInterfaceHL.
*
* @return RInterfaceHL singleton.
*/
public static RInterfaceHL getInstance() {
return SingletonHolder.INSTANCE;
}
}
/**
* Return the singleton instance of RInterfaceHL. Only the first call to
* this will establish the rloopHandler.
*
* @param rloopHandler
* R REPL handler supplied by client.
* @return RInterfaceHL singleton instance
* @throws REngineException
* if REngine cannot be created
*/
public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler)
throws REngineException {
RInterfaceHL.rloopHandler = rloopHandler;
RInterfaceHL instance = null;
try {
instance = SingletonHolder.getInstance();
} catch (ExceptionInInitializerError e) {
// rethrow exception that occurred in the initializer
// so our caller can deal with it
Throwable exceptionInInit = e.getCause();
throw new REngineException(null, exceptionInInit.getMessage());
}
return instance;
}
/**
* org.rosuda.REngine.REngine high level R interface.
*/
private REngine rosudaEngine = null;
/**
* Construct new RInterfaceHL. Only ever gets called once by
* {@link SingletonHolder.initRInterfaceHL}.
*
* @param rloopHandler
* R REPL handler supplied by client.
* @throws REngineException
* if R cannot be loaded.
*/
private RInterfaceHL(RMainLoopCallbacks rloopHandler)
throws REngineException {
// tell Rengine code not to die if it can't
// load the JRI native DLLs. This allows
// us to catch the UnsatisfiedLinkError
// ourselves
System.setProperty("jri.ignore.ule", "yes");
rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler);
}
}
答案 1 :(得分:4)
public class RInterfaceHL {
private static RInterfaceHL theInstance;
private final JRIEngine engine;
private RInterfaceHL(JRIEngine engine) {
this.engine = engine;
}
public static synchronized RInterfaceHL getInstance() {
if (theInstance == null) {
throw new IllegalStateException("not initialized");
}
return theInstance;
}
public static synchronized void initialize(String loopback) {
if (theInstance != null) {
throw new IllegalStateException("already initialized");
}
theInstance = new RInterfaceHL(new JRIEngine(loopback));
}
...
}
编辑:我应该补充一点,如果你要构建在servlet或类似容器中运行的东西,使用纯单例模式可能是一个坏主意。其中一个IoC /依赖注入机制是一个更好的主意;例如Spring在另一个答案中提出了建议。这允许您将“单身人士”范围扩展到容器。
答案 2 :(得分:0)
如果你只是做一个小应用程序可能会有点过分,但像Spring Framework这样的依赖注入框架可以为你提供单例行为而无需手动构建和初始化静态对象。
依赖注入“容器”将构造并将您的单例及其依赖类连接在一起,并且可以配置为使您的对象成为容器中的单例实例。
如果您之前没有使用过Spring,那么学习曲线会有一些学习曲线,但这是一个非常受欢迎的框架,可能会很好地为您服务。