zoukankan      html  css  js  c++  java
  • 设计模式 之 单例模式

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/design_patterns_singleton

    singleton pattern

    主要目标:对象只创建一次,每次都获得先前第一次创建的对象而不创建新的对象。(最好在使用时创建对象)

    实现思想:使用静态方法getInstance得到对象,为了保证对象只能通过getInstance创建,使构造函数私有。

    主要麻烦在于:

    • 多线程环境下getInstance方法的调用可能产生多个对象
    • 使用synchronized关键字可能降低高并发效率

    单例模式有很多种,大多用于解决多线程环境下的效率问题,高并发场景通常使用某些固定方案(java常用内部类机制),一般情况下思想比较简单,从应用的角度感觉不必深究。

    (后面懒得用实际例子命名了,Log4j中获取的logger对象就使用了单例模式)

    
    /**
     * 简单实现
     *
     * 存在的问题:
     *
     * 当创建过程需要时间时,连续调用getInstance方法会导致创建多个对象,特别是涉及多线程时容易出问题。
    */
    class Singleton_problem {
        private static Singleton_problem m_singletonProblem = null;
        private Singleton_problem(){
            // ...
        }
        public static Singleton_problem getInstance(){
            if (m_singletonProblem == null)
                m_singletonProblem = new Singleton_problem();
            return m_singletonProblem;
        }
    }
    
    
    /**
     * 解决方案一: eager initialization
     *
     * 缺点在于没有lazy loading机制
     */
    class Singleton_eager{
        private static final Singleton_eager m_singleton = new Singleton_eager();
        private Singleton_eager(){
            // ...
        }
        public static Singleton_eager getInstance(){
            return m_singleton;
        }
    }
    
    
    /**
     * 解决方案二: lazy initialization
     *
     * 在进行高并发操作时可能造成系统性能降低,由于调用getInstance函数每次只能一个线程使用
     * 在后面的测试代码里时间不明显,通过线程池等方式可能会不一样
     */
    class Singleton_lazy{
        private static Singleton_lazy m_singleton = null;
        // 线程锁,加锁的位置每次只能运行一个线程
        public static synchronized Singleton_lazy getInstance(){
            if (m_singleton == null)
                m_singleton = new Singleton_lazy();
            return m_singleton;
        }
    }
    
    
    /**
     * 解决方案三: lazy initialization + 双重加锁
     *
     * 降低方案二中的等待用时,当对象创建后就不用通过锁判断,创建后没有效率问题。
     */
    class Singleton_lazy_double_lock{
        private static Singleton_lazy_double_lock m_singleton = null;
        // 线程锁,加锁的位置每次只能运行一个线程
        public static synchronized Singleton_lazy_double_lock getInstance(){
            //第一重判断
            if (m_singleton == null) { //锁定代码块
                synchronized (Singleton_lazy_double_lock.class) { //第二重判断
                    if (m_singleton == null) {
                        m_singleton = new Singleton_lazy_double_lock(); //创建单例实例
                    }
                }
            }
            return m_singleton;
        }
    }
    
    /** Initialization on Demand Holder,通过java内部类机制
     * 貌似是java的最优实现方式,依赖具体语言
     * 由于内部类对象依赖外部类对象,因此内部类中的静态成员会在外部类对象创建后得到,
     * 此时相当于在使用时才进行初始化。
     */
    class Singleton_holder{
        private Singleton_holder() {
        }
        private static class HolderClass {
            private final static Singleton_holder instance = new Singleton_holder();
        }
        public static Singleton_holder getInstance() {
            return HolderClass.instance;
        }
        public static void main(String args[]) {
            Singleton_holder s1, s2;
            s1 = Singleton_holder.getInstance();
            s2 = Singleton_holder.getInstance();
            System.out.println(s1==s2);
        }
    }
    
    
    /**
     * 对上面的测试
     */
    public class Singleton{
    
        // 下面两个函数测试的结果使用两种方式的速度基本一致????
        // 线程创建和启动的时间过长,基本忽略了线程锁带来的时间差
    
        public static void time4singleton_lazy(){
            System.out.println("start");
            for(int i=0; i<10000; i++){
                Thread thread = new Thread() {
                    @Override
                    public void run() {
                        Singleton_lazy.getInstance();
                    }
                };
                thread.start();
            }
            System.out.println("end");
        }
    
        public static void time4singleton_eager(){
            int threadNum = 10000;
            Thread []threads = new Thread[threadNum];
            for(int i=0; i<threadNum; i++){
                threads[i] = new Thread() {
                    @Override
                    public void run() {
                        Singleton_eager.getInstance();
                    }
                };
            }
            System.out.println("start");
            for(int i=0; i<threadNum; i++)
                threads[i].start();
            System.out.println("end");
        }
    
        public static void main(String []argvs){
            //time4singleton_lazy();
            time4singleton_eager();
    
        }
    
    }
    
  • 相关阅读:
    <<浪潮之巅>>阅读笔记三
    <<浪潮之巅>>阅读笔记二
    <<浪潮之巅>>阅读笔记一
    《需求工程——软件建模与分析》阅读笔记三
    个人总结
    学习进度条(第十六周)
    人月神话阅读笔记03
    第十五周学习进度条
    人月神话阅读笔记02
    操作
  • 原文地址:https://www.cnblogs.com/fly2wind/p/13328079.html
Copyright © 2011-2022 走看看