java设计模式(二)--单例模式

本文深入解析单例模式(Singleton Pattern),探讨其在Java设计模式中的应用。文章详细介绍了单例模式的概念,即确保一个类只有一个实例,并提供全局访问点。讨论了单例模式的两种主要实现方式:懒汉式和饿汉式,以及它们各自的优缺点。重点分析了懒汉式的线程安全问题,提出了三种解决方案:使用synchronized关键字、设置双重检查锁和通过classloader机制。最后对比了懒汉式和饿汉式的适用场景。
   单例模式(Singleton Pattern)是java设计模式最简单的设计模式之一,这是我在每一个解释单例模式的文章中都看到的一句话,
    首先,我想讲一下我对此设计模式的理解:

这种模式让指定类在系统中只有唯一一个他的实例,我感觉这种模式是不想因太多实例而造成实例不一致的现象,所以让指定的类只实例化一次。 网络上对单例模式的解释: 这种模式涉及到单一的一个类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。 此模式的几点注意事项: 单例类只有一个实例 单例类必须自己创建自己的唯一实例 单例类必须给其他多有对象提供这一实例

    此设计模式主要有两种实现方法:懒汉式、饿汉式。

    我们的单例类的构造器要用private关键字,因为我们要防止此类通过构造器来进行实例化(其实,java中的反射机制是可以运行私有的构造器的,以至于破坏这个规则的,现在我们先不考虑这个)

    首先,懒汉式又有两种不同的路线,一种是线程安全的,一种是线程不安全的。
    (对于线程安全,就是当两个或者多个线程同时访问同一个资源的时候,可能会发生与单线程运行结果不同的现象,这样就说明线程不安全,反之,如果多线程与单线程运行结果相同的话,那就是线程安全的。)

首先先来看一下线程不安全的懒汉式的代码写法: public class LazySingletonDanger { private static Person p;

private LazySingletonDanger(){}

public static Person getInstance(){
	//如果实例为空,就新建一实例,这样保证了实例的唯一性
	if(p==null){
		p=new Person();
	}
	return p;
}

}

    以上这样的写法,如果多线程的话,会使很多线程共同运行同一段代码,会产生线程不安全的可能,所以以上代码是有安全隐患的。
    那么,如果我们要让这种安全隐患消失,要怎么做呢?
    答案是,有三种实现线程安全的方法:

    1.synchronized 关键字实现线程安全:

    public class LazySingletonSecure {
    private static Person p;
        private LazySingletonSecure(){}
         public static synchronized Person getInstance(){
	        if(p==null){
		    p=new Person();
	        }
	        return p;
        }
}
这是一个最简单地解决方案,但也是性能最差的解决方案
首先,加上synchronized关键字后,这个写法实现了线程安全,但是每次实例化时都要进行加锁操作,这样反而降低了性能。

    2. 设置双重校检锁保证线程安全

public class LazySingletonSecure {
private static Person p;
     private LazySingletonSecure(){}
  	public static Person getInstance2(){
			if(p==null){
				synchronized(Person.class){
				if(p==null){
					p=new Person();
				}
			}
		}
		return p;
}

} 这个要比第一个的性能损耗低点,因为,在同步的前面有一个判断非空的语句,这样就说明,除第一次实例化类时会进行加锁操作,之后就都不用进行加锁操作了,这样既实现了线程的安全,有提高了性能。 3.通过classloader机制来保证线程安全 (对于classloader,就是通过java中的类加载机制,动态的将用到的class文件,这样也差不多就是和懒汉式的意思差不多,都是用到的时候再将文件加载进来) public class LazySingletonSecure { /** * 通过内部类实例化类 * @author Administrator * */ private static class Lazy{ private final static Person PP=new Person(); } private LazySingletonSecure(){} public static final Person getInstance3(){ return Lazy.PP; }

    }
    这种方法是最好的解决单例模式的线程不安全的方法,既没有性能的损耗,又能实现线程安全,原理就是用一个内部类,java有一个机制,内部类只有在getInstance3方法第一次调用的时候才会被调用,所以,这种解决方法,实现了线程安全,资源利用,降低性能损耗,所以这应该是最完美的懒汉式的实现方法。

    然后,还有饿汉式,饿汉式就没有懒汉式那么多东西了,它本身就是线程安全的,看看饿汉式的实现代码吧:

public class HungrySingleton {
	private final static Person p=new Person();

	private HungrySingleton(){}

		//通过静态访问此类来返回实例化后的类
	 public static Person getInstance(){
			return p;
	 }
}
    但是这种饿汉式方法也是有缺点的,如果所创建的实例占空间很大而又长时间不用的话,这样就会造成资源浪费,这一点就不如懒汉式了,什么时候用什么时候才拿过来。

转载于:https://my.oschina.net/u/3631883/blog/1499023

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值