java之设计模式-单例模式

1.定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容不一致等错误。

例如:windows的回收站,操作系统中的文件系统,多线程中的线程池,打印机的后台处理服务,应用程序的日志对象,数据库的连接池,网站的计数器,web应用的配置对象,应用程序的对话框?

单例模式的特点:

a.单例类只有一个实例对象;

b.该单例对象必须由单例类自行创建;

c.单例类对外提供一个访问该单例的全局访问点。

2.单例模式的结构与实现

  单例模式是设计模式中最简单的模式之一,通常,普通类的构造函数是共公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的共有函数用于创建或获取该静态私有实例。

2.1 单例模式的结构

  单例模式的主要角色如下:

 2.2 单例模式的实现方式

步骤其实都是3步:

1.首先他不能被外部类实例化,所以构造方法必须用private关键字,第一步就是先写一个私有的构造方法。

private Singleton(){  };

2.因为只能自己实例化自己,所以,要自己创建一个对象。以下哪个都可以,一个属于懒汉式,一个属于饿汉式。

private static Singleton instance;    //懒汉式

private static HungrySingleton instance = new Singleton();   //饿汉式

3.要想外部访问到这个对象,那么必须定义一个public方法,这样把自己创建的对象传进去,让外部类使用才可以。

public static Singleton getInstance()

  { return instance; }

第一种,懒汉:该模式的特点是因为比较懒,类加载时没有生成单例,只有当第一次调用getInstance方法时才去创建这个单例。代码如下:

线程不安全的:因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class LazySingleton { private LazySingleton(){ } private static LazySingleton instance; public static LazySingleton getInstance(){ if(instance == null){ instance = new LazySingleton(); } return instance; } }
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

第二种,饿汉式:直接创建对象,不管你有没有用,反正提前创建好了。就和怕饿着一样,先准备好吃的再说。

public class HungrySingleton {
    private HungrySingleton(){
    }

    private static HungrySingleton instance = new HungrySingleton();

    public static HungrySingleton getInstance(){
        return instance;
    }
}

测试以上的是不是同一个对象:结果显示对象地址都一样,是同一个。

import org.testng.annotations.Test;

public class TestModel {
    @Test
    public  void test() {
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        HungrySingleton hungrySingleton1 = HungrySingleton.getInstance();
        System.out.println(hungrySingleton);
        System.out.println(hungrySingleton1);
        System.out.println(hungrySingleton == hungrySingleton1);
        assert hungrySingleton == hungrySingleton1;

    }

    @Test
    public  void test1() {
        LazySingleton lazySingleton = LazySingleton.getInstance();
        LazySingleton lazySingleton1 = LazySingleton.getInstance();
        System.out.println(lazySingleton);
        System.out.println(lazySingleton1);
        System.out.println(lazySingleton == lazySingleton1);
        assert lazySingleton == lazySingleton1;

    }
}

第三种:双检锁/双重校验锁(DCL,即 double-checked locking)

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

其他的参考:https://www.runoob.com/design-pattern/singleton-pattern.html

原文地址:https://www.cnblogs.com/peiminer/p/13638173.html