Question

J'ai une classe (RInterfaceHL) qui appelle une autre classe (JRIEngine) qui fournit des méthodes natives sur une application à un seul thread. Par conséquent, je ne souhaite disposer que d'une seule instance de ma classe (RInterfaceHL) par machine virtuelle.

Je peux utiliser le modèle singleton avec une initialisation statique pour ne garantir qu'une seule instanciation de RInterfaceHL, mais RInterfaceHL doit créer une instance de JRIEngine et lui fournir un paramètre de bouclage. Comment puis-je fournir, de manière sécurisée pour les threads, une seule instance de RInterfaceHL qui accepte un paramètre de bouclage pour la construction d'un seul moteur JRIE? J'utilise JDK6.

NB: La question portant le même nom ne répond pas à ma question.

Était-ce utile?

La solution

Modification du modèle Singleton utilisant la initialisation de Bill Pugh à l'idiome du titulaire de la demande . Ceci est thread-safe sans la surcharge de constructions de langage spécialisé (volatiles ou synchronisées):

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

Autres conseils

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: Je devrais ajouter que si vous créez des éléments à exécuter dans une servlet ou un conteneur similaire, l’utilisation du modèle Singleton pur est probablement une mauvaise idée. Un des mécanismes d’injection IoC / dépendance est une meilleure idée; par exemple. Printemps comme suggéré dans une autre réponse. Cela vous permet d’étudier votre & singles singletons " au conteneur.

Cela peut être excessif si vous ne faites qu'une petite application, mais un framework d'injection de dépendance comme Spring Framework peut vous donner un comportement singleton sans avoir besoin de construire et d’initialiser manuellement l’objet statique à la main.

L'injection de dépendance " conteneur " construira et reliera votre singleton et ses classes de dépendance ensemble, et pourra être configuré pour faire de votre objet une instance de singleton dans le conteneur.

Si vous n’avez jamais utilisé Spring, la courbe d’apprentissage est un peu longue, mais c’est un framework très populaire qui vous servira probablement bien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top