zoukankan      html  css  js  c++  java
  • 单例模式--笔记

    单例模式是一种对象创建型模式,使用单例模式,可以保证一个类只能唯一的生成一个实例化对象

    GoF对单例模式的定义:保证在一个类中,只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

    在应用开发系统中,我们常常需要以下需求:

    1).在多线程之间,如servlet环境,共享同一个资源或者操作同一个对象

    2).在整个程序空间启用全局变量,共享资源

    3).大规模系统中,为了性能的考虑,需要节省对象的创建时间等等

    因为Singleton模式可以保证为一个类只生成唯一的一个实例对象,所以对于上述情况,Singleton模式就派上用场了。

    单例模式实现:

    1.饿汉式;

    2.懒汉式;

    3.双重检查

    一般实现:

     1 public class Person{
     2    
     3     priate String name;
     4    
     5     public String getName(){
     6      
     7       return name;
     8      } 
     9     public String setName(){
    10      
    11       return this.name=name;
    12      } 
    13    
    14    
    15    }

    主类:

     1 public class MainClass{
     2   public static void main(String[] args){
     3     
     4     Person per=new Person();
     5     Person per2=new Person();
     6     //定义变量
     7     per.setName("张三");
     8     per2.setName(“李四”);
     9     //通过person类生成了两个对象
    10     System.out.println(per.getName());
    11     System.out.println(per2.getName());
    12 
    13   }
    14 }

    此时,在非单例模式下,定义两个对象,得到了输出结果为:

    张三

    李四

    首先展示的是饿汉式:

     1 public class Person{
     2    
     3     priate String name;
     4     public static final Person person =new person();//饿汉式设置
     5      //
     6     public String getName(){
     7      
     8       return name;
     9      } 
    10     public String setName(){
    11      
    12       return this.name=name;
    13      } 
    14     //构造函数私有化
    15     private person(){
    16    
    17    }
    18    //构造一个全局的静态方法:因为如果不是全局的,那么需要通过对象来进行调用,如果定义成全局的静态,就可以通过类来调用
    19    public static Person getPerson(){
    20      return new Person();
    21       }
    22    }

    此时,对于主类修改为:

     1 public class MainClass{
     2     public static void main(String[] args){
     3     Person per=Person.getPerson();//不再使用new来定义对象,用类定义
     4     Person per2=Person.getPerson();
     5      //定义变量
     6      per.setName("张三");
     7      per2.setName("李四");
     8     //通过person类生成了两个对象
     9      System.out.println(per.getName());
    10      System.out.println(per2.getName());
    11  
    12    }
    13  }

    得到的结果为:

    李四

    李四

    懒汉式:

     1 public class Person{
     2     
     3    priate String name;
     4     private static Person person;//静态初始化默认为null
     5      public String getName(){
     6       return name;
     7       } 
     8     public String setName(){
     9       
    10        return this.name=name;
    11       } 
    12      //构造函数私有化
    13      private person(){    
    14     }
    15     public static Person getPerson(){
    16     //此处添加一个判断
    17      if(person==null)   person=new  Person;     
    18       return  person();
    19        }
    20     }

    结果为:

    李四

    李四

    上述两种情形各有所长,在饿汉式中,一加载Person类就进行初始化对象,保证同一个对象

    在上述懒汉式中,可以保证单线程正常单例模式

    允许多线程的懒汉式单例模式:

     1 public class Person{
     2    
     3     priate String name;
     4     private static Person person;//静态初始化默认为null
     5       public String getName(){
     6        return name;
     7        } 
     8     public String setName(){
     9       
    10         return this.name=name;
    11       } 
    12       //构造函数私有化
    13       private person(){    
    14      }
    15     //使用一个全局的静态方法,使用同步方式
    16      public static Synchrogazed Person getPerson(){
    17     //当有一个线程进来时,这个方法就被霸占了,对于进来的方法就是将执行完毕在允许其他线程进入
    18       if(person==null)  //第一步
    19          person=new  Person;  //   第二步
    20        return  person();//第三步  
    21        }
    22      }

    双重检查:

      原因:在上述的多线程代码段中,我们实现的是将整个方法都实现同步,

     经过思考,我们可以发现,对于只有第一次的时候才会执行if内的内容;整个方法锁死后,接下来第二次,第三次。。。进来的都要进行判断if语句,影响执行效率

     1   public class Person{
     2      
     3       priate String name;
     4       private static Person person;//静态初始化默认为null
     5         public String getName(){
     6          return name;
     7          } 
     8       public String setName(){
     9         
    10          return this.name=name;
    11        } 
    12        //构造函数私有化
    13        private person(){    
    14       }
    15      //使用一个全局的静态方法
    16       public static  Person getPerson(){
    17      //当有一个线程进来时,这个方法就被霸占了,对于进来的方法就是将执行完毕在允许其他线程进入
    18        if(person==null) { //第一步
    19           Synchrogazed(Person.class){//仅仅同步化这一部分
    20           if(person==null)//这个判断语句添加的原因 当有两个线程进来时,第一个线程和第二个线程都执行完 
    // if(person==null)这条语句,第一个线程进入同步,第二个线程等待,当第一个线程执行完,
    //return之后,第二个线程又会执行同步语句,及时第一个线程已经new了一个对象,所以为防止这个情况的发生,
    //需要在同步里边再判断一次,也就是第二次判断
    21 person=new Person();} 22 } // 第二步 23 return person();//第三步 24 } 25 }
  • 相关阅读:
    各国语言缩写列表,各国语言缩写-各国语言简称,世界各国域名缩写
    How to see log files in MySQL?
    git 设置和取消代理
    使用本地下载和管理的免费 Windows 10 虚拟机测试 IE11 和旧版 Microsoft Edge
    在Microsoft SQL SERVER Management Studio下如何完整输出NVARCHAR(MAX)字段或变量的内容
    windows 10 x64系统下在vmware workstation pro 15安装macOS 10.15 Catelina, 并设置分辨率为3840x2160
    在Windows 10系统下将Git项目签出到磁盘分区根目录的方法
    群晖NAS(Synology NAS)环境下安装GitLab, 并在Windows 10环境下使用Git
    使用V-2ray和V-2rayN搭建本地代理服务器供局域网用户连接
    windows 10 专业版安装VMware虚拟机碰到的坑
  • 原文地址:https://www.cnblogs.com/lujun1949/p/5721174.html
Copyright © 2011-2022 走看看