大话设计模式——单例模式(Singleton)

单例模式(Singleton)是java中一个比较常见的设计模式,单例对象主要是为了保证在一个JVM中,该对象只有一个实例存在。主要优点:java

(1) 减小一些大型对象的开销,减小内存的占用面试

(2) 省去了new操做,较少了GC的压力设计模式

(3) 保证了一些核心类只被建立一次,好比一些核心的调度类,一些主要的操做类只被建立一次。安全

单例模式最多见的两种实现模式:饿汉式,懒汉式,内部静态类实现,双重检验锁模式函数

1.饿汉式:在进行类加载时就建立好 (添加了synchronized保证了线程的安全性)优化

package designPatterns;

public class SingletonHungry {
	
	private static SingletonHungry instance = new SingletonHungry();
	
	//私有构造函数,防止被实例化
	private SingletonHungry(){
		
	}
	
	public static SingletonHungry getInstance(){ 
		return instance;
	}

}   

 

2. 懒汉式:延迟加载,在用到的时候才进行建立spa

package designPatterns;

public class SingletonLazy {
    
    private static SingletonLazy instance = null;
    
    //私有构造函数,防止被实例化
    private SingletonLazy(){
        
    }

    public static SingletonLazy getInstance(){
        if(instance == null){
            instance = new SingletonLazy();
        }
        return instance;
    }
}

固然懒汉模式是线程不安全的,为了保证线程安全,咱们能够将函数定义成synchronized的,可是实际上,并非每次都须要同步的,只是在第一次建立对象的时候须要确保同步,所以咱们能够只同步一个对象。以下线程

package designPatterns;

public class SingletonLazy {
	
	private static SingletonLazy instance = null;
	
	//私有构造函数,防止被实例化
	private SingletonLazy(){
		
	}

	/*
	public static SingletonLazy getInstance(){
		if(instance == null){
			instance = new SingletonLazy();
		}
		return instance;
	}
	*/
	
	public static SingletonLazy getInstance(){
		if(instance == null){
			synchronized(instance){
				if(instance == null){
					instance = new SingletonLazy();
				}
			}
		}
		return instance;
	}
}

  可是,因为java中建立对象和赋值操做是分开进行的,也就是说instance = new SingletonLazy()这句话是分步执行的。JVM的即时编译存在指令重派的优化,2,3步的操做是没法肯定的。设计

       1. 给instance分配内存code

       2. 调用构造函数初始化成员变量

       3. 将instance对象指向分配的内存空间(执行完这句话以后instance才会变成非null的)

 

两步执行的,可能先执行分配空间,再初始化,这也可能会致使A,B两个线程不一样步,因此还有一种方法是使用内部静态类来进行实现,内部静态类在另外一篇博客中有详细介绍,这里再也不赘述。

3. 静态内部类,代码以下:

package designPatterns;

public class Singleton {
    
    //私有构造方法,防止被实例化
    private Singleton(){
        
    }
    
    //静态内部类建立实例
    private static class SingletonFactory{
        private static Singleton instance = new Singleton();
    }
    
    //获取实例
    public static Singleton getInstance(){
        return SingletonFactory.instance;
    }
    
    //若是该对象被用于序列化,能够保证对象在序列化先后保持一致
    public Object readResolve(){
        return getInstance();
    }

}

使用内部静态类的方法,只有在外部类被调用时才会被加载,而后new一个实例,这样就避免了锁的应用,通常建议使用这种方法,但仍是须要根据实际须要来进行选择的。

 

4. 双重检验锁模式(虽然内部类的方法感受更加好用一些,可是不少面试官想让你写的仍是双检锁模式)

public class Singleton {
    private volatile static Singleton instance; //volatile的可见性
    private Singleton() {}
    public static Singleton getSingleton() {
        if(instance == null) {         //Single Check
            synchronized(Singleton.class) {
                if(instance == null) {      //Double Check
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双检锁模式其实就是为了保证一个顺序。双检锁的出现保证了上述2,3句的执行顺序。

相关文章
相关标签/搜索