Java单例模式(复习)

单例模式的概念:

    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例
    Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
    Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
    一般Singleton模式通常有三种形式:

第一种形式:懒汉式,也是常用的形式。(就是屌丝,穷,不给准备好,担心饿死。类加载就给准备好 )
public class SingletonClass{
    private static SingletonClass instance=null;
    public static synchronized SingletonClass getInstance(){
        if(instance==null){
               instance=new SingletonClass();
        }
        return instance;
    }
    private SingletonClass(){
    }
}
第二种形式:饿汉式(就是有钱,豪,用的时候再new(线程不安全))
//对第一行static的一些解释
// java允许我们在一个类里面定义静态类。比如内部类(nested class)。
//把nested class封闭起来的类叫外部类。
//在java中,我们不能用static修饰顶级类(top level class)。
//只有内部类可以为static。
public class Singleton{
    //在自己内部定义自己的一个实例,只供内部调用
    private static final Singleton instance = new Singleton();
    private Singleton(){
        //do something
    }
    //这里提供了一个供外部访问本class的静态方法,可以直接访问
    public static Singleton getInstance(){
        return instance;
    }
}
比较:  饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
  懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
  推荐使用第一种 
  从实现方式来讲他们最大的区别就是懒汉式是延时加载,
  他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,
  饿汉式无需关注多线程问题、写法简单明了、能用则用。但是它是加载类时创建实例(上面有个朋友写错了)、所以如果是一个工厂模式、缓存了很多实例、那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。
  懒汉式的优点是延时加载、缺点是应该用同步(想改进的话现在还是不可能,比如double-check)、其实也可以不用同步、看你的需求了,多创建一两个无引用的废对象其实也没什么大不了。

    第三种形式: 双重锁的形式。( 这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。避免土豪模式下创建单例,可能存在的线程不安全问题。)
    /** 
     * 静态方法同步的时候,使用的锁,就不能是this,而是类.class 
     */  
public class Singleton{
    private static volatile Singleton instance=null;
    private Singleton(){
        //do something
    }
    public static  Singleton getInstance(){
        if(instance==null){
          //这个地方可能有多个线程,在这排队,ABCD..。  
            synchronized(Singleton.class){
                    //假设第一次A线程走到这,然后,呈挂起状态。这个时候,单例对象还未创建;  
                    // 假设此时,B线程也来了判断单例对象==null成立,但是,因为A线程已经给里层的if判断上锁,所以,B只能在外等着。  
                    //假设A线程被唤醒,那么,单例就会下面语句赋值,单例对象就创建啦。然后释放锁。B就可以进来啦。  
                    //B线程进来之后,先判断单例对象是否为null,发现已经不是null啦,那么就不需要创建啦。  
                    //CD线程同样,  
                    //再往后面来的,第一个if就进不来啦,那就不会判断锁了。 
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
     }
}
//这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。
//这种模式中双重判断加同步的方式,比第一个例子中的效率大大提升,因为如果单层if判断,在服务器允许的情况下,
//假设有一百个线程,耗费的时间为100*(同步判断时间+if判断时间),而如果双重if判断,100的线程可以同时if判断,理论消耗的时间只有一个if判断的时间。
//所以如果面对高并发的情况,而且采用的是懒汉模式,最好的选择就是双重判断加同步的方式。

优缺点


优点
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性

缺点
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
勿忘初心 得过且过
原文地址:https://www.cnblogs.com/xpf1009/p/9227290.html