Единственное создание с аргументами - PullRequest
4 голосов
/ 11 сентября 2009

У меня есть класс (RInterfaceHL), который вызывает другой класс (JRIEngine), который предоставляет нативные методы в однопоточном приложении. Поэтому я хочу иметь только один экземпляр моего класса (RInterfaceHL) для каждой JVM.

Я могу использовать одноэлементный шаблон со статической инициализацией, чтобы обеспечить только один экземпляр RInterfaceHL, но RInterfaceHL должен создать экземпляр JRIEngine и предоставить ему параметр loopback. Как я могу обеспечить потокобезопасным способом единственный экземпляр RInterfaceHL, который принимает параметр обратной связи для создания одного JRIEngine? Я использую JDK6.

NB: Этот вопрос с аналогичным названием не отвечает на мой вопрос.

Ответы [ 3 ]

6 голосов
/ 14 сентября 2009

Модификация шаблона Singleton, использующего Инициализация Билла Пью по требованию держателя . Это потокобезопасно без дополнительных затрат на специализированные языковые конструкции (то есть volatile или синхронизированные):

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 голосов
/ 11 сентября 2009
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));
    }

    ...
}

РЕДАКТИРОВАТЬ: я должен добавить, что если вы создаете вещи для запуска в сервлете или подобном контейнере, использование чистого шаблона Singleton, вероятно, плохая идея. Один из механизмов IoC / внедрения зависимостей - лучшая идея; например Весна, как это предлагается в другом ответе. Это позволяет вам размещать ваши "синглеты" в контейнере.

0 голосов
/ 11 сентября 2009

Это может быть излишним, если вы просто делаете небольшое приложение, но инфраструктура внедрения зависимостей, такая как Spring Framework , может дать вам одноэлементное поведение без необходимости вручную создавать и инициализировать статический объект вручную.

Внедрение зависимостей «контейнер» сконструирует и свяжет вас вместе singleton и его классы зависимостей, и его можно настроить так, чтобы ваш объект был единичным экземпляром в контейнере.

Есть некоторая кривая обучения, если вы раньше не использовали Spring, но это действительно популярная среда, и, вероятно, она вам пригодится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...