Frage

Ich habe eine Klasse (RInterfaceHL), die eine andere Klasse (JRIEngine) nennt, die auf einer Single-Threaded-Anwendung native Methoden zur Verfügung stellt. Deshalb möchte ich nur eine einzige Instanz meiner Klasse (RInterfaceHL) pro JVM haben.

kann ich das Singletonmuster mit statischer Initialisierung verwendet nur eine einzige Instantiierung RInterfaceHL zu gewährleisten, sondern RInterfaceHL muss eine Instanz von JRIEngine konstruieren und sie mit einem Loopback-Parametern liefern. Wie kann ich bieten, in einer Thread-sichere Weise eine einzelne Instanz RInterfaceHL, die für den Bau eines einzigen JRIEngine einen Loopback-Parameter akzeptiert? Ich verwende JDK6.

. NB: Diese ähnlich benannten Frage meine Frage nicht beantwortet

War es hilfreich?

Lösung

Modifikation von Singleton-Muster, die Bill Pugh Initialisierung auf Anfrage Halter Idiom verwendet. Dies ist Thread sicher ohne den Overhead von spezialisierten Sprachkonstrukten (d.h. flüchtige oder synchronisiert):

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

Andere Tipps

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

    ...
}

EDIT: Ich sollte hinzufügen, dass, wenn Sie Sachen bauen in einem Servlet oder einem ähnlichen Behälter zu laufen, das reine Singleton-Muster verwendet, ist wahrscheinlich eine schlechte Idee. Einer der IoC / Dependency Injection Mechanismen ist eine bessere Idee; z.B. Frühling wie in einer anderen Antwort vorgeschlagen. So können Sie den Gültigkeitsbereich „Singletons“ in den Behälter.

Es könnte zu viel des Guten, wenn Sie nur eine kleine Anwendung zu tun, aber ein Dependency Injection-Framework wie Spring Framework können Sie Singleton Verhalten geben, ohne die Notwendigkeit von Hand das statische Objekt manuell zu konstruieren und initialisieren.

Die Dependency Injection „Container“ wird konstruieren und Draht Sie Singletons und seine Abhängigkeit Klassen zusammen und kann so konfiguriert werden, um Ihr Objekt eine Singleton-Instanz innerhalb des Behälters zu machen.

Es ist ein bisschen eine Lernkurve, wenn Sie nicht Frühling verwendet haben, aber es ist ein wirklich beliebt Rahmen, und wird wahrscheinlich dienen Sie gut.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top