2009-09-11 5 views
4

단일 스레드 응용 프로그램에서 원시 메서드를 제공하는 다른 클래스 (JRIEngine)를 호출하는 클래스 (RInterfaceHL)가 있습니다. 따라서 JVM 당 하나의 클래스 (RInterfaceHL) 인스턴스 만 갖고 싶습니다.인수가있는 단일 인스턴스화

정적 초기화시 싱글 톤 패턴을 사용하여 RInterfaceHL의 단일 인스턴스 만 보장 할 수 있지만 RInterfaceHL은 JRIEngine 인스턴스를 생성하고 루프백 매개 변수를 제공해야합니다. 단일 JRIEngine 구축을위한 루프백 매개 변수를 허용하는 RInterfaceHL의 단일 인스턴스를 스레드로부터 안전한 방식으로 어떻게 제공 할 수 있습니까? JDK6을 사용하고 있습니다.

NB : This 마찬가지로 이름이 질문은 내 질문에 대답하지 않습니다.

+1

참고하지만, 클래스 로더 당이 전문 언어 구조의 오버 헤드없이 스레드로부터 안전합니다 (즉, 휘발성 또는 동기화)입니다. Java에서의 싱글 톤 패턴은 클래스에 인스턴스 작성과 실제 책임이라는 두 가지 책임을 부여함으로써 얻어집니다. 인스턴스 생성 책임은 클래스가 클래스 로더에 의해로드 될 때 처리됩니다 (JVM 당 여러 클래스 로더가있을 수 있음). –

답변

6

Bill Pugh's initialization on demand holder idiom을 사용하는 싱글 톤 패턴의 수정. 싱글 톤은 JVM 당 아니라는 것을

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); 
    } 
} 
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)); 
    } 

    ... 
} 

편집 : 순수 싱글 톤 패턴을 사용하면 서블릿이나 비슷한 컨테이너에서 실행할 물건을 만드는 경우에는 나쁜 아이디어라고 덧붙여 야합니다. IoC/의존성 주입 메커니즘 중 하나가 더 좋은 아이디어입니다. 예 : 다른 답변에서 제안 된대로 봄. 이렇게하면 "싱글 톤"을 컨테이너 범위로 지정할 수 있습니다.

0

방금 ​​작은 응용 프로그램을 작성하는 경우 과장 될 수 있지만 Spring Framework과 같은 종속성 주입 프레임 워크는 수동으로 정적 객체를 수동으로 만들고 초기화 할 필요없이 단독 동작을 제공 할 수 있습니다.

종속성 삽입 "컨테이너"는 사용자에게 단일 클래스와 종속성 클래스를 구성하고 연결하며 컨테이너 내에서 객체를 단일 인스턴스로 만들도록 구성 할 수 있습니다.

이전에 Spring을 사용하지 않았다면 약간의 학습 곡선이 있지만 실제로는 널리 사용되는 프레임 워크이므로 잘 처리 할 수 ​​있습니다.

관련 문제