zoukankan      html  css  js  c++  java
  • 设计模式之——单例模式

    单例模式属于创建模式的一种,在Java中也是最重要、最简单、最常用的设计模式之一,当遇到以下情况时,单例模式就派上用场了。

    再比如——对象。。。。。。。。。。。

    一般一个类能否做成单例,最容易区别的地方就在于,这些类,在应用中如果有两个或者两个以上的实例会引起错误,又或者我换句话说,就是这些类,在整个应用中,同一时刻,有且只能有一种状态。

    单例模式的实现方法主要有四种:饿汉式、懒汉式、工厂方法、枚举方法。前两者是比较常见的的实现方法,当然如果面试时能将后两项也完美阐述的话,说明你的水平可不是一般货色可比的..>.<..下面贴代码,主要阐述都在注释里。。

    一、饿汉式

    package Singleton;
    /*
     * 单例模式
     * 应用场合:有些对象只需一个就可以了
     * ①要求生成唯一序列号的环境
     * ②在整个项目中需要一个共享访问点或共享数据
     * ③需要定义大量的静态常量和静态方法(如工具类)的环境,可以使用单例
     * ④创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源 
     * 
     * 作用:保证整个应用程序中某个实例只有一个,并提供一个访问他的全局访问点
     * 类型:饿汉模式,懒汉模式
     * 
     * */
    public class Singleton {
        //饿汉模式:缺点是类实例化后不能添加逻辑
        
        //1.将构造方法私有化,不允许外部直接创建对象
        private Singleton(){
            
        }
        //2.创建类的唯一实例         static 静态的可将其变为类的成员
       private static final Singleton instance=new Singleton();    
        
        //3.提供一个用于获取实例的方法
        public static Singleton getInstance(){
            return instance;
        }
        
    }

    二、懒汉式

    package Singleton;
    /*
     * 懒汉模式:只声明实例,并没有实例化
     * 但类加载时,并没有创建实例,而当用户获取时,开始做判断(是否为空),若为空,才创建实例
     * 创建之后(第2、3、4···)再来获取时,由于实例已存在,就不会再创建实例了
     * 
     * */
    
    
    public class Singleton2 {
        //懒汉模式
        
       //1.将构造方法私有化,不允许外部直接创建对象
        private Singleton2(){
            
        }
        //2.声明类的唯一实例,使用private static 修饰
        private static Singleton2 instance;
        
        //3.提供一个用于获取实例的方法,使用public static修饰
          public static Singleton2 getInstance(){
              if(instance==null){    //多线程下不安全
                  instance=new Singleton2();
              }
              return instance;
          }    
        
    }

    三、工厂化方法,可以在创建实例过程中添加逻辑(主要针对懒汉式的缺点)

    package Singleton;
    /**
     * 工厂化方法:可以在实例过程中添加逻辑
     * */
    public class Singleton3 {
    
        private Singleton3(){
            
        }
        private static Singleton3 instance=new Singleton3();
        
        public static Singleton3 getInstance(){
            return instance;
        } 
        
    }

    四、枚举类方法(注意是 ~枚举 ~ 类   enum),最佳推荐,代码最简洁  **.**

    package Singleton;
    /**
     * 枚举类方式:最佳实践,推荐
     * effective java 推荐
     * */
    public enum Singleton4 {
        instance;
    }

    五、对前四种单例方法验证一下,注意看实例创建的方式

    package Singleton;
    
    /*懒汉模式和饿汉模式的区别:
     * 懒汉模式:加载类时比较快,但运行时获取对象的速度比较慢,线程不安全
     * 饿汉模式:加载类时比较慢,但运行时获取对象的速度比较快(因对象早已创建好),线程安全
     * 
     * 
     * */
    
    
    
    public class TestSingleton {
        //饿汉模式
        public static void main(String[] args) {
            System.out.println("饿汉模式");
            Singleton s1=Singleton.getInstance();
            Singleton s2=Singleton.getInstance();
            if(s1==s2){
                System.out.println("s1和s2是同一个实例");
            }else{
                System.out.println("s1和s2是同一个实例");
            }
            
            
            //懒汉模式
            System.out.println("懒汉模式");
            Singleton2 s3=Singleton2.getInstance();
            Singleton2 s4=Singleton2.getInstance();
            if(s3==s4){
                System.out.println("s3和s4是同一个实例");
            }else{
                System.out.println("s3和s4不是同一个实例");
            }
            
            
            //工厂方法
            System.out.println("工厂方法模式");
            Singleton3 s5=Singleton3.getInstance();
            Singleton3 s6=Singleton3.getInstance();
            if(s5==s6){
                System.out.println("s5和s6是同一个实例");
            }else{
                System.out.println("s5和s6不是同一个实例");
            }
         
            
            //枚举
            System.out.println("枚举");
            Singleton4 s7=Singleton4.instance;
            Singleton4 s8=Singleton4.instance;
            if(s7==s8){
                System.out.println("s7和s8是同一个实例");
            }else{
                System.out.println("s7和s8不是同一个实例");
            }
            
        }
    }

    运行结果:

    六、针对最经典的懒汉模式易造成线程不安全的问题再多加一句废话

    为什么说懒汉式是最经典的呢?因为饿汉模式这种方式最主要的缺点就是一旦我访问了Singleton的任何其他的静态域,就会造成实例的初始化,而事实是可能我们从始至终就没有使用这个实例,造成内存的浪费。

    假设n个线程,当并发访问的时候,第一个调用getInstance方法的线程A,在判断完singleton是null的时候,线程A就进入了if块准备创造实例,但是同时另外一个线程B在线程A还未创造出实例之前,就又进行了singleton是否为null的判断,这时singleton依然为null,所以线程B也会进入if块去创造实例,这时问题就出来了,有两个线程都进入了if块去创造实例,结果就造成单例模式并非单例。

  • 相关阅读:
    2010全球最值得模仿的230个网站 dodo
    IIS支持解析json dodo
    很好用的界面设计工具——Balsamiq dodo
    git本地分支目录和远程服务器的分支目录不一样的同步方法
    中新赛克——基于工业资产全息画像的工业互联网安全监测平台 规格严格
    解决redis requires ruby version 2.3.0[转载] 规格严格
    fpm包安装 规格严格
    git本地分支目录和远程服务器的分支目录不一样的同步方法[转】 规格严格
    MyBatis逆向工程generatorConfig配置文件的Table中generatedKey的作用[转载] 规格严格
    How to set character_set_database and collation_database to utf8 in my.ini 规格严格
  • 原文地址:https://www.cnblogs.com/zjfjava/p/6496042.html
Copyright © 2011-2022 走看看