详解Java实现单例的五种方式

  

<强>
  

  

单例模式指的是在应用整个生命周期内只能存在一个实例。单例模式是一种被广泛使用的设计模式。他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内存。
  

  

单例模式的要求有三点:

  
      <李>某个类只能有一个实例   <李>它必须自行创建这个实例   <李>他必须自行向整个系统提供整个实例   
  


  

  

首先理解一下什么是静态类,静态类就是一个类里面都是静态方法和静态,构造器被私人修饰,因此不能被实例化.Math类就是一个静态类。

  

知道了什么是静态类后,来说一下他们两者之间的区别:

  

1)首先单例模式会提供给你一个全局唯一的对象,静态类只是提供给你很多静态方法,这些方法不用创建对象,通过类就可以直接调用;

  

2)单例模式的灵活性更高,方法可以被覆盖,因为静态类都是静态方法,所以不能被覆盖;

  

3)如果是一个非常重的对象,单例模式可以懒加载、静态类就无法做到;

  

那么时候时候应该用静态类,什么时候应该用单例模式呢?首先如果你只是想使用一些工具方法,那么最好用静态类,静态类比单例类更快,因为静态的绑定是在编译期进行的。如果你要维护状态信息,或者访问资源时,应该选用单例模式。还可以这样说,当你需要面向对象的能力时(比如继承,多态)时,选用单例类,当你仅仅是提供一些方法时选用静态类。

  


  

  

<强> 1。饿汉模式

  

所谓饿汉模式就是立即加载,一般情况下再调用getInstancef方法之前就已经产生了实例,也就是在类加载的时候已经产生了。这种模式的缺点很明显,就是占用资源,当单例类很大的时候,其实我们是想使用的时候再产生实例。因此这种方式适合占用资源少,在初始化的时候就会被用到的类。

        类SingletonHungary {   私有静态SingletonHungary SingletonHungary=new SingletonHungary ();//将构造器设置为私人禁止通过新的进行实例化   私人SingletonHungary () {      }   公共静态SingletonHungary getInstance () {   返回singletonHungary;   }   }   之前      

<强> 2。懒汉模式

  

懒汉模式就是延迟加载,也叫懒加载。在程序需要用到的时候再创建实例,这样保证了内存不会被浪费。针对懒汉模式,这里给出了5种实现方式,有些实现方式是线程不安全的,也就是说在多线程并发的环境下可能出现资源同步问题。

  

首先第一种方式,在单线程下没问题,在多线程下就出现问题了。

     //单例模式的懒汉实现1——线程不安全   类SingletonLazy1 {   私有静态SingletonLazy1 singletonLazy;      私人SingletonLazy1 () {      }      公共静态SingletonLazy1 getInstance () {   如果(null==singletonLazy) {   尝试{//模拟在创建对象之前做一些准备工作   thread . sleep (1000);   }捕捉(InterruptedException e) {   e.printStackTrace ();   }   singletonLazy=new SingletonLazy1 ();   }   返回singletonLazy;   }   }      之前      

我们模拟10个异步线程测试一下:

        公开课SingletonLazyTest {      公共静态void main (String [] args) {      Thread2 [] ThreadArr=new Thread2 [10];   for (int i=0;我& lt;ThreadArr.length;我+ +){   新Thread2 ThreadArr[我]=();   ThreadArr[我].start ();   }   }      }//测试线程   类Thread2延伸线程{   @Override   公共空间run () {   .hashCode System.out.println (SingletonLazy1.getInstance () ());   }   }      之前      

运行结果:

  
  

124191239
  124191239
  872096466
  1603289047
  1698032342
  1913667618
  371739364
  124191239
  1723650563
  367137303
  

     

可以看到他们的hashCode不都是一样的,说明在多线程环境下,产生了多个对象,不符合单例模式的要求。

  

那么如何使线程安全呢?第二种方法,我们使用同步关键字对getInstance方法进行同步。

     //单例模式的懒汉实现2——线程安全//通过设置同步方法,效率太低,整个方法被加锁   类SingletonLazy2 {   私有静态SingletonLazy2 singletonLazy;      私人SingletonLazy2 () {      }      公共静态同步SingletonLazy2 getInstance () {   尝试{   如果(null==singletonLazy) {//模拟在创建对象之前做一些准备工作   thread . sleep (1000);   singletonLazy=new SingletonLazy2 ();   }   }捕捉(InterruptedException e) {   e.printStackTrace ();   }   返回singletonLazy;   }   }      

详解Java实现单例的五种方式