• 单例模式【java版】


    一、基本特点

          如何防止创建多个实例:构造方法设置为私有,使得外部无法直接new出实例

          基本组成:a)一个静态的和自身类型相同的成员对象

                          b)私有的构造方法

                          c)获取实例的公有方法,供外部调用,以返回实例

           

    二、懒汉式

    特点:类被加载时不创建实例,getInstance方法第一次被调用时才创建实例

    类代码:

    public class LazySingleton {

    /**
    * 静态的和自身类型相同的成员对象
    */
    private static LazySingleton theLazySingleton=null;

    /**
    * 构造方法设置为私有,保证无法从外部new出实例
    * LazySingleton myLazySingleton=new LazySingleton();这样的语句就无法通过编译
    */
    private LazySingleton(){}

    /**
    * 供外部调用的获取实例的方法,会在第一次调用时初始化实例
    */
    public static LazySingleton getInstance(){

    if(theLazySingleton==null){
    System.out.println("懒汉式单例,第一次调用,先创建,再返回实例!");
    theLazySingleton=new LazySingleton();
    }else{
    System.out.println("懒汉式单例,已不是第一次调用,直接返回实例!");
    }

    return theLazySingleton;
    }

    }

    主函数:

        public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("开始测试单例模式!");

    //尽管使用了两个引用名,实际上指向的是内存中同一个实例
    LazySingleton myLazySingleton_A, myLazySingleton_B;

    myLazySingleton_A=LazySingleton.getInstance();
    myLazySingleton_B=LazySingleton.getInstance();
    }

    运行结果:

    三、饿汉式

    特点:类被加载时就创建实例

    类代码:

    public class HungrySingleton {

    private static final HungrySingleton theHungrySingleton=new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){

    System.out.println("饿汉式单例,实例已在类加载时被创建,故可直接返回实例!");

    return theHungrySingleton;
    }

    }

    主函数:

        public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("开始测试单例模式!");

    HungrySingleton myHungrySingleton=HungrySingleton.getInstance();
    }

    运行结果:

    四、多线程环境下的单例模式

        A)线程安全的单例:

      1、效率较高线程安全单例(常用方式
                “静态内部类”只在getInstance()方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的(实现线程安全)

        基本理论依据:java的class-loading是线程安全的

         详细参考:http://bbs.csdn.net/topics/360053719

    //静态内部类实现懒汉式  
    public class Singleton {  
          
        private static class SingletonHolder{  
            //单例变量    
            private static Singleton instance = new Singleton();  
        }  
          
        //私有化的构造方法,保证外部的类不能通过构造器来实例化。  
        private Singleton() {  
              
        }  
          
        //获取单例对象实例  
        public static Singleton getInstance() {  
            System.out.println("我是内部类单例!");  
            return SingletonHolder.instance;  
        }  
    } 

      2、效率较低线程安全单例
                a)懒汉式,静态方法getInstance前加“类锁”
                    缺点:每次获取实例时都会对类进行加锁操作,影响性能

             实际只需第一次instance==null时加类锁,防止内存中创建了两个实例。

    public class Singleton {  
          
        //单例实例变量  
        private static Singleton instance = null;  
          
        //私有化的构造方法,保证外部的类不能通过构造器来实例化  
        private Singleton() {}  
          
        //获取单例对象实例  
        public static synchronized  Singleton getInstance() {  
              
            if (instance == null) {   
                instance = new Singleton();   
            }  
              
            System.out.println("我是同步法懒汉式单例!");  
            return instance;  
        }  
    }  

                b)饿汉式
                     缺点: 一些未必需要加载的模块会每次都被加载,影响整个系统初次加载速度

    public class Singleton {  
          
        //单例变量 ,static的,在类加载时进行初始化一次,保证线程安全   
        private static Singleton instance = new Singleton();      
          
        //私有化的构造方法,保证外部的类不能通过构造器来实例化。       
        private Singleton() {}  
          
        //获取单例对象实例       
        public static Singleton getInstance() {  
            System.out.println("我是饿汉式单例!");  
            return instance;  
        }  
    } 

       B) java“写无序”导致的“非线程安全单例”:双重锁定懒汉式

    //双重锁定懒汉式  
    public class Singleton {  
          
        //单例实例变量  
        private static Singleton instance = null;  
          
        //私有化的构造方法,保证外部的类不能通过构造器来实例化  
        private Singleton() {}  
          
        //获取单例对象实例  
        public static Singleton getInstance() {  
            if (instance == null) {   
                synchronized (Singleton.class) {  
                    if (instance == null) {   
                        instance = new Singleton();   
                    }  
                }  
            }  
            System.out.println("我是双重锁定懒汉式单例!");  
            return instance;  
        }  
    }  

      java内存模型中的“无序写”(out-of-order writes)机制,

      可能导致:intance<>null时,只是intance=mem,而mem=allocate()还没有完成。

      所谓的“无序写”就是,单条语句instance=new Singleton()

      实际执行时为两条语句:1、mem=new Singleton()

                 2、instance=mem

      而这两个操作是无序的

      PS:整条语句执行完,肯定instance中的值是正确的,但两步中间可能有其他线程进来访问instance。

      参考:http://www.2cto.com/kf/201310/249105.html

         http://blog.csdn.net/liushuijinger/article/details/9069801

  • 相关阅读:
    昆石VOS3000_2.1.4.0完整安装包及安装脚本
    KVPhone,VOS官方的SIP软电话电脑客户端
    昆石VOS2009 VOS3000无漏洞去后门电脑管理客户端大全
    2017年最新(4月20日)手机号码归属地数据库分享
    2017年最新VOS2009/VOS3000最新手机号段导入文件(手机归属地数据)
    Android:onNewIntent()
    三星S4使用体验(Markdown版)
    apple公司的潮起潮落——浪潮之巅
    microsoft的罗马帝国——浪潮之巅
    我的iOS开发之路
  • 原文地址:https://www.cnblogs.com/edisonfeng/p/2221305.html
Copyright © 2020-2023  润新知