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

    一、引言

      今天笔者想写的设计模式——单例模式,其意图就是为了使系统有且仅有一个实例化,也就是一个对象我只有new一次就够了,也是像我们平凡人一样,婚结一次就够了,但是现在的社会啊,我只能以“理想很丰满,现实很骨感”来形容了,让我们一起了解下单例设计模式吧。

    二、单例模式

      1. 定义:它是比较简单的一个模式,就是确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

      2. 类图:单纯的单例模式,其实就一个类,所以在此处就省略一下类图吧。

    三、单例模式示例

      1. 懒汉式  

    package com.pattern.singleton.core;
    
    /**
     * 单例——懒汉式
     * 典型的以时间换空间方式
     * @author yemaoan
     *
     */
    public class Singleton {
    
        private static Singleton singleton;
        
        private Singleton() {    //注意是private哦
            
        }
        
        public static Singleton getInstance() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }

      2. 饱汉式

    package com.pattern.singleton.core;
    
    /**
     * 单例——饿汉式
     * 典型的以空间换时间方式
     * @author yemaoan
     *
     */
    public class Singleton {
    
        public static Singleton singleton = new Singleton();
        
        private Singleton() {
            
        }
        
        public static Singleton getInstance() {
            return singleton;
        }
    }

    四、单例模式应用

      单例看起来就是如上面的两种情况一样,相当简单,如果真的这么认为单例就这样完了,那你可能真的可能完了。说不定哪一天你的婚姻真的因插入一个小三给毁了,当然,言重了,那让我们分析一下弊病吧。

      在大数据的背景下,并发处理就不可或缺了,而只是简简单单的单例就可能经不起压力测试了,从源码分析上,很容易就发现在问题所在了。怎么解决了,暂且可以在getSingleton()方法前加个关键字synchronized来解决吧。

      解决线程不安全的方法挺多的,具体情况具体分析吧。笔者推荐一个:

    package com.pattern.singleton.core;
    
    /**
     * 利用static在JVM启动时只实例化一次确保对象唯一
     * @author yemaoan
     *
     */
    public class Singleton {
    
        private Singleton() {
            
        }
    
        public static Singleton getInstance() {
            return SingletonInstance.instance;
        }
    
        //静态类——在Java应用启动只实例化一次,确实instance的唯一
        private static class SingletonInstance {
            static Singleton instance = new Singleton();
        }
        
    }

       写个例子测试一下吧——就拿上文写的策略算法映射Service来写吧,为什么这么选择呢,也许有这么一个需求,笔者认为,这个类其实也就是一个服务类,很多细节是在开发前就已经配置好的,或者说在数据库里已经定义好的,这样的话,就想当一个工具类。

    package com.pattern.stategy.factory;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.pattern.stratgy.core.Car;
    import com.pattern.stratgy.core.Plane;
    import com.pattern.stratgy.core.Train;
    
    /**
     * 算法映射——改装成单例
     * @author yemaoan
     *
     */
    public class ContentService {
    
        private Map<String, Class> contentMap = new HashMap<String, Class>();
        
        private ContentService() {
            contentMap.put("train", Train.class);
            contentMap.put("plane", Plane.class);
            contentMap.put("car", Car.class);
        }
        
        public static ContentService contentServiceInstance() {
            return ContentServiceInstance.instance;
        }
    
        private static class ContentServiceInstance {
            static ContentService instance = new ContentService();
        }
        
        public Class get(String key) {
            return contentMap.get(key);
        }
        
    }

      调用者代码:

    package com.pattern.singleton.client;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.pattern.stategy.factory.ContentService;
    
    /**
     * 
     * @author yemaoan
     *
     */
    public class ContentServiceThread extends Thread {
        
        private static List<ContentService> list = new ArrayList<ContentService>();
        private String name;
        
        public ContentServiceThread(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            for(int index = 0; index < 5; index++) {
                ContentService contentService = ContentService.contentServiceInstance();
                list.add(contentService);
                System.out.print(this.name + "  ");
            }
        }
        
        public static void main(String[] args) throws InterruptedException  {
            //启动四线程,每线程生成5个ContentService
            //thread begin
            new ContentServiceThread("A").start();
            new ContentServiceThread("B").start();
            new ContentServiceThread("C").start();
            new ContentServiceThread("D").start();
            //thread end
            Thread.sleep(2000);
            System.out.println();
            System.out.println("当前对象总数为:" + list.size());
            for(int index = 0; index < list.size(); index++) {
                System.out.println((index+1) + " : " + list.get(index));
            }
        }
    }

      笔者用了四个线程,每个线程生成5个ContentService对象,让我们看一下具体运行效果:

    B  A  D  C  D  A  B  A  D  C  D  A  B  A  D  C  B  C  B  C  
    当前对象总数为:20
    1 : com.pattern.stategy.factory.ContentService@1034bb5
    2 : com.pattern.stategy.factory.ContentService@1034bb5
    3 : com.pattern.stategy.factory.ContentService@1034bb5
    4 : com.pattern.stategy.factory.ContentService@1034bb5
    5 : com.pattern.stategy.factory.ContentService@1034bb5
    6 : com.pattern.stategy.factory.ContentService@1034bb5
    7 : com.pattern.stategy.factory.ContentService@1034bb5
    8 : com.pattern.stategy.factory.ContentService@1034bb5
    9 : com.pattern.stategy.factory.ContentService@1034bb5
    10 : com.pattern.stategy.factory.ContentService@1034bb5
    11 : com.pattern.stategy.factory.ContentService@1034bb5
    12 : com.pattern.stategy.factory.ContentService@1034bb5
    13 : com.pattern.stategy.factory.ContentService@1034bb5
    14 : com.pattern.stategy.factory.ContentService@1034bb5
    15 : com.pattern.stategy.factory.ContentService@1034bb5
    16 : com.pattern.stategy.factory.ContentService@1034bb5
    17 : com.pattern.stategy.factory.ContentService@1034bb5
    18 : com.pattern.stategy.factory.ContentService@1034bb5
    19 : com.pattern.stategy.factory.ContentService@1034bb5
    20 : com.pattern.stategy.factory.ContentService@1034bb5

    五、总结

      1. 单例在设计模式中是比较简单的一个了,它是用途主要是保证一个类有且只有一个实例化对象。

      2. 单例在多线程中需要注意一下并发产生对象不一的情况,这也许在压力过程中就能体现出来。

    六、题外话

      在这里就事论事地说一下,有人也许会认为直接把一个对象设置成一个全局变量就得了,何必这么纠结呢?呵呵,笔者认为,一个全局变量毕竟是一开始就要初始化创建,耗资源呐,再说倘若后期没用了,怎么办,岂不是白白浪费了......而采用单例的话,那又不同说法了,毕竟单例是我们需要的时候才去创建,再者单例模式可以确保一个对象只有被实例化一次。

  • 相关阅读:
    javaScript系列 [35]HTML页面渲染的基本过程
    javaScript系列 [29] RegExp
    javaScript系列 [40]defineProperty
    javaScript系列 [32] type
    javaScript系列 [34]FormData
    javaScript系列 [39]deepClone
    javaScript系列 [33] new
    javaScript系列 [36]Call by sharing
    javaScript系列 [38]浏览器、HTML和内核(引擎)
    javaScript系列 [28] Event
  • 原文地址:https://www.cnblogs.com/maoan/p/3354287.html
Copyright © 2011-2022 走看看