views:

171

answers:

3

I have a class (RInterfaceHL) that calls another class (JRIEngine) which provides native methods on a single-threaded application. Therefore I only want to have a single instance of my class (RInterfaceHL) per JVM.

I can use the singleton pattern with static initialization to ensure only a single instantiation of RInterfaceHL, but RInterfaceHL needs to construct an instance of JRIEngine and supply it with a loopback parameter. How can I provide, in a thread-safe manner, a single instance of RInterfaceHL that accepts a loopback parameter for construction of a single JRIEngine? I'm using JDK6.

NB: This similarly named question does not answer my question.

+2  A: 
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");
        }
    }
    public static synchronized void initialize(String loopback) {
        if (theInstance != null) {
            throw new IllegalStateException("already initialized");
        }
        theInstance = new RInterfaceHL(new JRIEngine(loopback));
    }

    ...
}

EDIT: I should add that if you are building stuff to run in a servlet or similar container, using the pure Singleton pattern is probably a bad idea. One of the IoC / dependency injection mechanisms is a better idea; e.g. Spring as suggested in another answer. This allows you to scope your "singletons" to the container.

Stephen C
A: 

It might be overkill if you're just doing a small application, but a dependency injection framework like Spring Framework can give you singleton behavior without the need to manually construct and initialize the static object by hand.

The dependency injection "container" will construct and wire you singleton and its dependency classes together, and can be configured to make your object a singleton instance within the container.

There's a bit of a learning curve if you haven't used Spring before, but it's a really popular framework, and will probably serve you well.

Andy White
+2  A: 

Modification of Singleton pattern that uses Bill Pugh's initialization on demand holder idiom. This is thread safe without the overhead of specialized language constructs (i.e. volatile or 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);
    }
}
tukushan