我有一个类 (RInterfaceHL),它调用另一个类 (JRIEngine),它在单线程应用程序上提供 native 方法。因此,我只想为每个 JVM 拥有我的类 (RInterfaceHL) 的单个实例。
我可以使用带有静态初始化的单例模式来确保 RInterfaceHL 的单个实例化,但 RInterfaceHL 需要构造 JRIEngine 的实例并为其提供回送参数。如何以线程安全的方式提供 RInterfaceHL 的单个实例,该实例接受用于构建单个 JRIEngine 的环回参数?我正在使用JDK6。
注意:This 类似命名的问题不能回答我的问题。
最佳答案
修改使用 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);
}
}