代码之家  ›  专栏  ›  技术社区  ›  tekumara

带有参数的单一实例化

  •  5
  • tekumara  · 技术社区  · 16 年前

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

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

    注意: This 这个名字相似的问题没有回答我的问题。

    3 回复  |  直到 9 年前
        1
  •  6
  •   tekumara    16 年前

    使用Singleton模式的修改 Bill Pugh's initialization on demand holder idiom 这是线程安全的,没有专门的语言构造(即volatile或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);
        }
    }
    
        2
  •  4
  •   Debosmit Ray    8 年前
    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/依赖注入机制之一是一个更好的主意;例如,另一个答案中提到的春天。这允许您将“单例”范围限定到容器。

        3
  •  0
  •   Andy White    16 年前

    如果你只是做一个小应用程序,但像这样的依赖注入框架可能有点过头了 Spring Framework 可以为您提供单例行为,而无需手动构造和初始化静态对象。

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

    如果你以前没有使用过Spring,那么学习曲线会有点长,但它是一个非常受欢迎的框架,可能会对你很有帮助。