Java设计模式之单例模式

    单例模式是很常见的设计模式,当某个类在整个系统中只需要存在一个对象时,比如说一个管理整个服务器配置的类,它的实例在系统中只能存在一个,这个时候就需要使用单例模式来确保这个类不会被实例化第二次。单例模式是Java所有设计模式中类图最简单的模式,但这并不代表单例模式就很简单。

    单例模式一般有懒汉式、饿汉式、双重检查、静态内部类和枚举等几种实现方式,实现方式各不相同,但一定有一点是相同的,这些实现方式首先都得把类的构造方法改为私有,这样才能防止直接被实例化。下面就来列举下这几种实现方式:

1懒汉式(线程不安全)
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	
	public static Singleton getInstance(){
		if(singleton == null){
			singleton = new Singleton();
		}
		return singleton;
	}
}
    所谓懒汉模式,顾名思义就是类比较懒,不通过调用getInstance()方法不会主动生成自己的实例。但是这个实现方式是线程不安全的,如果代码在多线程环境中运行,很可能会发生多个线程同时调用getInstance()方法从而导致实例化多次,多线程环境下不可使用。
2懒汉式(线程安全,同步方法)
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	
	public static synchronized Singleton getInstance(){
		if(singleton == null){
			singleton = new Singleton();
		}
		return singleton;
	}
}
    第二种方法在第一种的基础上对getInstance()方法加了个线程同步,这样子就是线程安全的实现方法了。这种方法虽然实现了线程安全,但是线程同步是加在getInstance()方法上的,每个线程想要获得实例时执行getInstance()方法都要进行同步,同步效率比较低,不推荐使用。
3懒汉式(线程安全,同步代码块)
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	
	public static Singleton getInstance(){
		if(singleton == null){
			synchronized (Singleton.class){				
				singleton = new Singleton();
			}
		}
		return singleton;
	}
}
    这种实现方式采用同步代码块的方式来代替同步方法的方式,效率的确变高了,但是这种实现方式和第一种一样并不能起到线程同步的作用。如果在线程A通过if(singleton == null)判断语句块开始执行同步代码块的时候,线程B也通过判断语句等待执行同步代码块。这样当线程A执行完毕同步代码块并释放的时候,Singleton类的实例实际上已经创建出来了,可是线程B已经通过判断语句进来了,所以类Singleton会被再次实例化, 多线程环境下不可使用。
4双重检查(线程安全,同步代码块)
public class Singleton {
	private volatile static Singleton singleton;
	private Singleton(){}
	
	public static Singleton getInstance(){
		if(singleton == null){
			synchronized (Singleton.class){
				if(singleton == null){
					singleton = new Singleton();
				}
			}
		}
		return singleton;
	}
}
   基于volatile的双重检查锁定方式很好的实现了单例模式,第一次检查时没有锁定,看看这个域是否被初始化了;第二次检查时有锁定。只有当第二次检查时表明这个域没有被初始化,才会生成类的实例。 因为如果域已经被初始化就不会有锁定,域被声明为volatile很重要!
5饿汉式(静态常量)
public class Singleton {
	private final static Singleton SINGLETON = new Singleton();
	private Singleton(){}
	
	public static Singleton getInstance(){
		return SINGLETON;
	}
}
   这种实现方式之所以叫做“饿汉式”,是因为不管getInstance()方法是否有被调用,它都会在类装载的时候完成实例化。但是这样就不能够实现延迟加载,如果这个类的实例比较大,那么实例所占的内存在需要被实例化前就消耗掉了,比较浪费内存。
6 饿汉式(静态代码块)
public class Singleton {
	private final static Singleton singleton;
	static{
		singleton = new Singleton();
	}
	private Singleton(){}
	
	public static Singleton getInstance(){
		return singleton;
	}
}
   这种实现方式和上面的实现方式类似,只不过将实例化的过程放在了静态代码块中,同样也是在类装载的时候完成了实例化。
7 静态内部类
public class Singleton {
	private Singleton(){}
	
	private static class Instance{
		private static final Singleton singleton = new Singleton();
	}
	
	public static Singleton getInstance(){
		return Instance.singleton;
	}
}
   这种实现方式和“饿汉式”实现原理类似,都是利用JVM的类装载机制来防止多次实例化。但是静态内部类的实现方式不会在类装载的时候就直接实例化,而是在调用getInstance()方法时才会装载内部类Instance,从而完成实例化。
8、枚举
public enum Singleton {
	INSTANCE;
	public void whateverMethod() {
		
	}
}
    这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值