zoukankan      html  css  js  c++  java
  • 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++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。
    
    勿忘初心 得过且过
  • 相关阅读:
    转载:DIV+CSS有可能遇到的问题
    CSS3那些不为人知的高级属性
    php获取GET方式传入的全部变量名称与值:foreach用法
    转载:Erlang 资源
    Java工具类 Apache Commons:commons-lang
    PHP安装环境,服务器不支持curl_exec的解决办法
    2018年5月10日论文阅读
    C++ code:char pointers and char arrays(字符指针与字符数组)
    2018年5月9日论文阅读
    C++ code:More Loop Designs
  • 原文地址:https://www.cnblogs.com/xpf1009/p/9227290.html
Copyright © 2011-2022 走看看