java 的设计模式-----单例模式。

基本面试时80%都会问到“你知道哪些设计模式”

一般我们回答 “经常用到的设计模式有单例模式,工厂模式等”,

设计模式有23种,既然你回答了单例模式,工厂模式,那接下来他又会问 “你项目中有用到单例模式吗?”

你说“有"

接下来他又会问”你项目中哪些用到了单例模式?为什么用?“

你说”项目中没有用到单例“

他又会问“那你了解单例模式吗,什么情况下用单例模式?“

你说”了解一点,不深,“

有的面试官会拿出纸笔让你写一段单例模式的代码出来。。。。。当然这是个别案例 ,我就遇到了。。。。

当你写完面试官又会问”单例也分懒汉,饿汉,你知道吗”

你说“知道”

“那这懒汉和饿汉又有什么区别?什么时候用懒汉什么时候用饿汉?

完了,这个话题有的聊。。。。。。。

因为经常遇到,今天来把这些整明白了,摔倒过的地方不能再摔倒。。。

所谓单例 ,指的就是单实例,有且仅有一个类的实例。

那我们什么时候用单例呢,

例如,有一个类statistical,这个类里有一个属性 number ,当有用户访问我们的网站时,我们就让number+1 ,这样能达到网站统计访问量的效果,因为我们知道要访问类的属性,需要先实例化这个类,但是每次new statistical() 都会是一个新的对象,为了让统计的访问量准确,这里statistical类就需要做成单例。

总结一句话,当某个资源共享时,这个资源需在的类需要单例。

单例模式有两种创建方式:懒汉式和饿汉式

不论是创建懒汉还是创建饿汉都有几个要点

  1.私有构造方法。

  2.私有静态引用指向自己实例 

  3.以自己实例为返回值的公有静态方法

饿汉式:意思饿了,饥不则食,只要有吃的必急着吃,在这里的意思就是:在加载类的时候就会创建类的实例,并保存在类中。

饿汉式代码片段:

//饿汉式
public class Test_eh {
	//此处定义私有类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中
    private static Test_eh instance = new Test_eh();
    //定义私有无参构造器,用于单例实例
    private Test_eh(){
    	
    }
    //定义公开方法,返回已创建的单例
    public static Test_eh getInstance(){
        return instance;
    }
}
饿汉式优点 
       1.线程安全 
       2.在类加载的同时已经创建好一个静态对象,调用时反应速度快 
饿汉式缺点 
       资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么            这个实例仍然初始化 


懒汉式:看字面意思就是一个字,懒,非得叫你才去干,在这里的意思就是,不在系统加载这个类时创建,而是在第一次使用的时候再创建。

懒汉式代码片段:

//懒汉式  
public class Test_lh {  
  //定义一个私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取  
  private static Test_lh instance = null;  
  //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建  
  private Test_lh(){  
        
  }  
  //定义一个公共的公开的方法来返回该类的实例,由于是懒汉式,需要在第一次使用时生成实例,  
  public static synchronized Test_lh getInstance(){  
      //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况,所以为了线程安全,
	  //使用synchronized关键字来确保只会生成单例  
      if(instance == null){  
          instance = new Test_lh();  
      }  
      return instance;  
  }  
} 

懒汉式优点:类的实例在第一次被使用时构建,延迟初始化。避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率                                高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。 

懒汉式缺点: 懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,解决这个问题的办法就是                         加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。

懒汉式实现单例模式中,有使用synchronized关键字来同步获取实例,保证单例的唯一性,但是上面的代码在每一次执行时都要进行同步和判断,会拖慢速度,使用双重加锁机制正好可以解决这个问题:

双重加锁机制片段:

//双重加锁式  
public class Test_lh_2 {  
      //定义一个私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,
	  //而要使用提供的公共方法来获取  
      private static volatile Test_lh_2 instance = null;  
      //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建  
      private Test_lh_2(){  
            
      }  
      //定义一个公共的公开的方法来返回该类的实例  
      public static Test_lh_2 getInstance(){  
          //第一重判断,如果单例已经存在,那么就不再需要进行同步操作,而是直接返回这个实例  
          if(instance == null){  
              /* 
               * 如果没有创建,才会进入同步块,同步块的目的与之前相同,目的是为了防止有两个
               * 调用同时进行时,导致生成多个实例, 有了同步块,每次只能有一个线程调用能访
               * 问同步块内容,当第一个抢到锁的调用获取了实例之后,这个实例就会被创建, 
               * 之后的所有调用都不会进入同步块,直接在第一重判断就返回了单例 
               */  
              synchronized (Test_lh_2.class) {  
                  if(instance == null){  
                      instance = new Test_lh_2();  
                  }  
              }  
          }  
          return instance;  
      }  
} 

使用了双重加锁机制后,程序的执行速度 有了显著提升,不必每次都同步加锁。

饿汉会占用较多的空间资源,因为在其类加载时就会完成实例化,而懒汉式又存在执行速率慢的情况,双重加锁机制又有执行效率差的毛病,网上还有一种完美的方式可以规避这些毛病,理解的不深,不做过多解释。

静态内部类代码片段:

//静态内部类方式  
public class Test {  
  /* 
   * 创建静态内部类,这种内部类与其外部类之间并没有从属关系,加载外部类的时候,并不会同时加载
   * 其静态内部类,只有在发生调用的时候才会进行加载,加载的时候就会创建单例实例并返回,有效
   * 实现了懒加载(延迟加载),至于同步问题, 我们采用和饿汉式同样的静态初始化器的方式,借
   * 助JVM来实现线程安全 
   */  
  public static class TestNBN{  
      private static Test instance = new Test();  
  }  
  //定义无参构造器,用于单例实例  
  private Test(){  
        
  }  
  //义公开方法,返回已创建的单例  
  public static Test getInstance(){  
      return TestNBN.instance;  
  }  
} 

总结: 

    在资源开销不大的情况下,一般采用饿汉式,若对资源十分在意可以采用静态内部类方式,不建议采用懒汉式及双重检测式。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值