单例模式--笔记

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

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 }
原文地址:https://www.cnblogs.com/lujun1949/p/5721174.html