单例模式(创建型)

Posted 无名小厨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式(创建型)相关的知识,希望对你有一定的参考价值。

单例模式(创建型设计模式)是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。它一共有懒汉式,饿汉式,双重加锁验证DCL,静态内部类,枚举创建五种创建方式。
1.懒汉式

public class Singleton 

    private final static  Singleton instance=new Singleton();

    private Singleton() 
    

    public static Singleton getInstance()
        return instance;
    

饿汉式的写法通常静态成员变量已经是初始化好的

  • 优点是可以不加锁就获取到对象实例,线程安全,
  • 主要的缺点在于不是延加载,稍微存在内存的浪费,因为如果初始化的逻辑较为复杂,比如存在网络请求或者一些复杂的逻辑在内,就会产生内存的浪费。
  1. 饿汉式
public class Singleton1 

    private  static  Singleton1 instance;
    private Singleton1() 
    
    public static synchronized Singleton1 getInstance()
        if(instance==null)
            instance=new Singleton1();
        
        return instance;
    


通过加同步锁实现

  • 优点解决了饿汉式浪费内存的问题,在真正需要获取实例对象的才去执行初始化。

  • 缺点效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行
    同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,

  1. 双重加锁验证DCL
public class Singleton2 
    private  volatile static Singleton2 instance;
    private Singleton2() 
    
    
    public static Singleton2 getInstance() 
        if (instance == null) 
            synchronized (Singleton2.class) 
                if (instance == null) 
                    instance = new Singleton2();
                
            
        
        return instance;
    

于是为了解决懒汉式性能的问题,双重加锁验证的写法诞生了,先判断一次空,真的为空再执行加锁,然后再判断一次。 这样的话,只有在实例对象是空的情况才会去加锁创建对象,性能问题得到了一定程度上的解决,也不会和饿汉一样有内存浪费的问题。
4. 静态内部类

public class Singleton3 

    private  static class  SingletonHolder
        private final  static Singleton3 SINGLETON_3=new             Singleton3();
    

    private Singleton3()
    

    public static  Singleton3 getInstance()
        return SingletonHolder.SINGLETON_3;
    

这个通过JVM来保证创建单例对象的线程安全和唯一性,是比较好的办法。
Singleton类加载的时候,SingletonHolder不会加载,只有在调用getInstance方法的时候才会执行初始化,这样既起到了懒加载的作用,同时又使用到了JVM类加载机制。
5. 枚举创建

public enum Singleton5 
    INSTANCE;
    public void doSomething() 
        System.out.println("doSomething");
    

解决线程安全和单一实例的问题,还可以防止反射和反序列化对单例的破坏

创建型设计模式(单例模式)

单例模式有以下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

一、懒汉式单例

//懒汉式单例类.在第一次调用的时候实例化自己   
public class Singleton {  
    private Singleton() {}  
    private static Singleton single=null;  
    //静态工厂方法   
    public static Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
    }  
}  

  以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全。

1、在getInstance方法上加同步

public static synchronized Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
}  

2、双重检查锁定

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

3、静态内部类

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return LazyHolder.INSTANCE;    
    }    
}

二、饿汉式单例

//饿汉式单例类.在类初始化时,已经自行实例化   
public class Singleton1 {  
    private Singleton1() {}  
    private static final Singleton1 single = new Singleton1();  
    //静态工厂方法   
    public static Singleton1 getInstance() {  
        return single;  
    }  
}  

  饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

  

  

以上是关于单例模式(创建型)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式理解创建型——单例原型

php 设计模式 - 单例

设计模式之单例模式

设计模式--单例模式(Singleton)

设计模式之单例模式

设计模式的征途—1.单例(Singleton)模式