문제
단일 스레드 응용 프로그램에서 기본 메소드를 제공하는 다른 클래스 (jriengine)를 호출하는 클래스 (rinterfacehl)가 있습니다. 따라서 JVM 당 단일 클래스 (rinterfacehl) 만 갖고 싶습니다.
정적 초기화와 함께 싱글 톤 패턴을 사용하여 rinterfacehl의 단일 인스턴스화 만 보장 할 수 있지만 rinterfacehl은 Jriengine 인스턴스를 구성하고 루프백 매개 변수를 제공해야합니다. 스레드 안전 방식으로 단일 Jriengine의 구성을위한 루프백 매개 변수를 수용하는 Rinterfacehl의 단일 인스턴스를 어떻게 제공 할 수 있습니까? JDK6을 사용하고 있습니다.
NB : 이것 마찬가지로 이름이 지정된 질문은 내 질문에 대답하지 않습니다.
해결책
사용하는 싱글 톤 패턴의 수정 Bill Pugh의 초기화에 대한 초기화 보유자 관용구. 이것은 특수 언어 구성 (즉, 휘발성 또는 동기화 된)의 오버 헤드가없는 스레드 안전입니다.
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);
}
}
다른 팁
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));
}
...
}
편집 : 서블릿이나 이와 유사한 컨테이너로 실행하기 위해 물건을 만들고 있다면 순수한 싱글 톤 패턴을 사용하는 것은 아마도 나쁜 생각이라고 덧붙여 야합니다. IOC / 의존성 주입 메커니즘 중 하나는 더 나은 아이디어입니다. 예를 들어 또 다른 대답에서 제안 된대로 봄. 이를 통해 "싱글 톤"을 컨테이너로 범위로 범위를 보일 수 있습니다.
작은 응용 프로그램을 수행하는 경우 과잉 일 수 있지만 의존성 주입 프레임 워크 봄 프레임 워크 수동으로 정적 객체를 수동으로 구성하고 초기화 할 필요없이 싱글 톤 동작을 줄 수 있습니다.
의존성 주입 "컨테이너"는 싱글 톤과 그 종속성 클래스를 함께 구성하고 와이어로 만들고 컨테이너 내의 싱글 톤 인스턴스를 만들도록 구성 할 수 있습니다.
전에 봄을 사용하지 않았다면 약간의 학습 곡선이 있지만 정말 인기있는 프레임 워크이며 아마도 당신에게 잘 섬길 것입니다.