Java设计模式--单例模式【Singleton Pattern】

      在宇宙中,太阳是唯一的,独一份的,不可复制的,人们每天抬头看到的太阳都是同一个,不会随着斗转星移就多产生一个太阳,所以太阳就是绝对的单例。下面就以“太阳”为例介绍单例模式。

     所谓单例模式就是保证一个类有且只有一个实例。要创建一个独一无二的对象实例,就必须保证程序其他地方不能创建出该单例对象的新实例。

    设计一个单例类时,需要确定何时初始化该类的单例对象。

    1、第一种做法是创建这个类的实例,并将它作为该类的静态成员变量。

package com.pattern.singleton.s2;

public class Sunshine {
  private static Sunshine singleton=new Sunshine();
  
  private Sunshine(){
	  
  }
  public static Sunshine getSunshine(){
	  return singleton;
  } 
}

初试化静态的singleton创建一次。如果我们在Sunshine类里面写一个静态的方法不需要创建实例,它仍然会早早的创建一次实例。而降低内存的使用率。缺点是没有延迟加载lazy loading的效果,从而降低内存的使用率。

2、如果不希望提前创建单例模式,就延迟初始化,在第一次需要它时再创建实例。这就是单例的第二种做法。

package com.pattern.singleton;

public class Sunshine {
  private static Sunshine singleton=null;
  
  private Sunshine(){//私有构造方法保证不能让其他地方创造第二个太阳
	  
  }
  public static Sunshine getSunshine(){
	  if(singleton==null){
		  singleton=new Sunshine();
	  }
	  return singleton;
  } 
}
如果把上述代码放到多线程的环境中,可能会出现两个或多个线程同时初始化一个单例对象的情况。假设第一个线程发现singleton 为null,紧接着第二个线程运行下拉也发现singleton为null,然后两个线程都会对该对象进行实例化。为了避免多个线程同时初始化对象实例,就必须改进上述单例模式设计方法,加入同步机制,实现多线程协调运行。

3、最简单的方式,就是在方法中加入synchronized实现线程同步。

package com.pattern.singleton.s1;

public class Sunshine {
  private static Sunshine singleton=null;
  
  private Sunshine(){//私有构造方法保证不能让其他地方创造第二个太阳
	  
  }
  public static synchronized Sunshine getSunshine(){
	  if(singleton==null){
		  singleton=new Sunshine();
	  }
	  return singleton;
  } 
  
}
加上了同步锁,使得在多线程的情况下可以用。例如:当两个线程同时想创建实例,由于在一个时刻只有一个线程能得到同步锁,当第一个线程加上锁以后,第二个线程只能等待。第一个线程发现实例没有创建,创建之。第一个线程释放同步锁,第二个线程才可以加上同步锁,执行下面的代码。由于第一个线程已经创建了实例,所以第二个线程不需要创建实例。保证在多线程的环境下也只有一个实例。但是每次通过getSunshine方法得到singleton实例的时候都有一个试图去获取同步锁的过程。加锁是很耗时的,效率太低,所以可以考虑将加锁的过程考虑到方法内。

4、这就出现了双重校验锁的单例模式

package com.pattern.singleton.s1;

public class Sunshine {
  private static Sunshine singleton=null;
  
  private Sunshine(){//私有构造方法保证不能让其他地方创造第二个太阳
	  
  }
  public static Sunshine getSunshine(){
	  if(singleton==null){
		  synchronized (Sunshine.class) {  
			  if(singleton==null){
				  singleton=new Sunshine();
			  }
		  }
	  }
	  return singleton;
  }  
}
只有当singleton为null时,需要获取同步锁,创建一次实例。当实例被创建,则无需试图加锁.缺点是用双重if判断太复杂,容易出错。

那么有没有一种方式,既可以做到延迟加载,又可以避免双重锁的机制呢?

5、匿名内部类-单例模式

package com.pattern.singleton.s1;

public class Sunshine {
  private Sunshine(){//私有构造方法保证不能让其他地方创造第二个太阳
		  
  }
  private static class SunshineFactory{
	  private final static Sunshine singleton=new Sunshine();
  }
  public static Sunshine getSunshine(){
	  return SunshineFactory.singleton;
  } 
}
定义一个私有的内部类,在第一次用这个嵌套类时,会创建一个实例。而类型为SunshineFactory的类,只有在Sunshine.getSunshine()中调用,由于私有的属性,他人无法使用SunshineFactory创建新实例。


源码下载:http://download.csdn.net/download/pelifymeng2/9994100

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值