设计模式——单例模式

1、引言

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

2、单例模式

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

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

3、单例模式示例

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

4、单例模式应用

  单例看起来就是如上面的两种状况同样,至关简单,若是真的这么认为单例就这样完了,那你可能真的可能完了。说不定哪一天你的婚姻真的因插入一个小三给毁了,固然,言重了,那让咱们分析一下弊病吧。多线程

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

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

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

5、总结

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

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

6、题外话

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

相关文章
相关标签/搜索