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


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

1.单例模式

 确保一个类只有一个实例,并提供一个全局访问点。

应用场景:对于我们只需要一个对象的场景,如线程池(threadpool)、缓存(cache),如果制造出多个实例,就会导致许多问题。

2.Singleton Pattern 类图

类变量持有唯一的单例实例,getInstance()方法是静态方法,可以直接使用Singleton.getInstance()获取实例,是全局访问点。


3.经典的单例模式实现方式

注意:经典单例模式是线程不安全的

代码:

/**  
 * 经典的单例模式:这是线程不安全的  
 * 注意:延迟实例化,即在我们需要这个实例的时候,才实例化  
 */  
public class Singleton {  
    //1.利用一个静态变量来记录Singleton类的唯一实例  
    private static Singleton uniqueInstance;  
  
    //这里可以有其他的有用的实例化变量  
  
    //2.把构造器声明为私有,只有Singleton类内才能调用构造器  
    private Singleton() {}  
  
    //3.使用静态方法getInstatnce()实例化对象,并返回这个实例  
    public static Singleton getInstance() {  
        if (uniqueInstance == null) {  
            uniqueInstance = new Singleton();  
        }  
        return uniqueInstance;  
    }  
    //这里是其他有用的方法  
}  

 

4.处理多线程场景下的单例模式

方法:将getInstance()方法同步成synchronized方法即可解决。

我们迫使每个线程进入这个方法之前,要先等候别的线程离开该方法,即不会有两个线程可以同时进入这个方法。

代码:

public class Singleton {
	private static Singleton uniqueInstance;
	private Singleton() {}
 
	public static synchronized Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
}

缺点:性能问题,只有在第一次创建实例的时候,才需要真正的同步,以保证唯一得到实例化变量,

一旦uniqueInstance设置OK之后,就不需要同步这个方法,之后每次同步造成性能下降。

5.Singleton Pattern 在多线程下提高性能的方法

a.如果getInstance()的性能对应用程序不是很关键,就什么不做。

b.使用“急切”创建实例,而不用延迟实例化的做法

public class Singleton {
	private static Singleton uniqueInstance = new Singleton();
	private Singleton(){};
	public static Singleton getInstance(){
		return uniqueInstance;
	}
}
使用这种做法之后,对象会在JVM加载这个类时就创建,不管需不需要实例化的对象。

c.使用双重检查加锁,在getInstance()中减少使用同步

思路:首先检查实例是否创建,如果尚未创建,才在创建的部分进行同步,这样一来,只用在第一次创建是才进行同步。

补充:volatile关键字知识

不能保证操作的原子性,但是可以保证操作的是同一个变量的同一个内存。用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。
volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)。

双重检查锁实现代码:

// 双重检查加锁不适用1.4及更早版本的Java
public class Singleton {

	private volatile static Singleton uniqueInstance;
	private Singleton() {}
 
	public static Singleton getInstance() {
		//检查实例,如果不存在,就进入同步区
		if (uniqueInstance == null) {
			//只有第一次才彻底执行这里的代码
			synchronized (Singleton.class) {
				if (uniqueInstance == null) {
					uniqueInstance = new Singleton();
				}
			}
		}
		return uniqueInstance;
	}
}


加锁前后2次判断实例是否已经存在:


class Singleton{
	private Singleton(){}
	private static Object syncObj = new Object();
	private static Singleton instance = null;
	public static Singleton getInstance (){
		if (instance == null){
			lock (syncObj){
				if (instance == null){
					instance = new Singleton();
				}
			
			}
		return instance;
		}
	}
} 




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值