2009-09-11 28 views
4

我有一个类(RInterfaceHL)调用另一个类(JRIEngine),它在单线程应用程序上提供了本机方法。因此,我只想为每个JVM有一个类(RInterfaceHL)的单个实例。带参数的单实例化

我可以使用静态初始化的单例模式来确保RInterfaceHL只有一个实例化,但RInterfaceHL需要构造一个JRIEngine实例并为其提供一个环回参数。我如何以线程安全的方式提供RInterfaceHL的单个实例,该实例接受构建单个JRIEngine的环回参数?我正在使用JDK6。

注:This同样命名的问题不回答我的问题。

+1

请注意,单例不是每个JVM,而是每个类加载器。 Java中的单例模式是通过使类具有双重责任 - 实例创建和实际责任而获得的。当类加载类加载器时会处理实例创建责任(并且每个JVM可能有多个类加载器)。 – 2009-09-11 05:03:24

回答

6

修改使用Bill Pugh's initialization on demand holder idiom的单例模式。这是线程安全的,没有专用语言结构(即易失性或同步)的开销:

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

    ... 
} 

编辑:我要补充一点,如果你正在建设的东西在servlet或类似容器中运行,使用纯Singleton模式可能是一个坏主意。 IoC /依赖注入机制之一是一个更好的主意;例如春天在另一个答案建议。这使您可以将您的“单身人士”范围限定在容器中。

0

如果你只是在做一个小应用程序,但是依赖注入框架如Spring Framework可以给你单例行为,而不需要手动构造和初始化静态对象,这可能是矫枉过正的。

依赖注入“容器”将构造并将单例及其依赖类连接在一起,并可配置为使对象成为容器内的单例实例。

如果您之前没有使用过Spring,那么有一点学习曲线,但它是一个非常流行的框架,并且可能会很好地为您服务。