23种常用设计模式(一)单例模式

一、单例模式的定义

单例模式 :确保某个类只有一个实例,且自行实例化并向整个系统提供这个实例。

二、单例模式的优缺点及应用场景

优点:单例模式在内存中只有一个实例,大大减少了内存开支,特别是一个对象需要频繁地创建、销毁时,单例模式的优势就非常明显。单例模式可以在系统设置全局的访问点,优化和共享资源访问。

缺点:单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

使用场景:在一个系统中,要求一个类有且仅有一个对象,或者创建一个对象需要消耗的资源过多,都可以使用单例模式;如spring中的bean对象默认是单例模式。

三、单例模式示例代码

3.1、饿汉式

//饿汉式单例,在类初始化时创建,线程安全
public class Singleton {
	//构造方法私有化,防止外界创建
    private Singleton() {}
    //创建对象
    private static final Singleton single=new Singleton();
    //获取实例对象
    public static Singleton getInstance() {
        return single;
    }
} 

3.2、懒汉式

//懒汉式单例.在第一次调用的时候创建,线程不安全
public class Singleton {
	//构造方法私有化,防止外界创建
    private Singleton() {}
    private static final Singleton single=null;//单例对象
    
    public static Singleton getInstance() {
    	if (single == null) {  
             	single = new Singleton();
         	}  
        return single;
    }
} 

懒汉式单例模式在低并发的情况下尚不会出现问题,若系统压力增大,并发量增加时则可能在内存中出现多个实例,破坏了最初的预期。

如一个线程A执行到singleton= new Singleton(),但还没有获得对象(对象初始化是需要时间的),第二个线程B也在执行,执行到(singleton == null)判断,那么线程B获得判断条件也是为真,于是继续运行下去,线程A获得了一个对象,线程B也获得了一个对象,在内存中就出现两个对象!

要实现线程安全,有以下三种方式:

1、在getInstance方法上加锁同步

public class Singleton {
	//构造方法私有化
    private Singleton() {}
    private static final Singleton single=null;//单例对象
    
    public static synchronized Singleton getInstance() {//同步锁
    	if (single == null) {  
             	single = new Singleton();
         	}  
        return single;
    }
}

此方法虽保证了线程安全,但每次调用都要获取锁,对性能有很大影响。

2、双重检查

public class Singleton {
	//构造方法私有化
    private Singleton() {}
    //volatile保证可见性和禁止指令重排序
    private volatile static Singleton single=null;
    
    public static Singleton getInstance() {
    	if (single == null) { // 第一重检查锁定
			synchronized (Singleton.class) {//同步锁
				if (single == null) { // 第二重检查锁定
             		single = new Singleton();
         		}
         	}  
         }
        return single;
    }
}

此方法比第一种好一些,只有第一次访问(还未创建对象)才需要获取锁。

3、静态内部类

  public class Singleton {  
    private static class LazyHolder {
    	//被调用时加载
       private static final Singleton single= new Singleton();  
    }  
    private Singleton (){}  
    
    public static Singleton getInstance() {  
       return LazyHolder.single;  
    }  

使用内部类的好处是,静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,达到了类似懒汉模式的效果,而这种方法又是线程安全的,同时又避免了同步锁带来的性能影响。

上一篇:1121 Damn Single (25 分)


下一篇:1121 Damn Single (25分)