设计模式之单例设计模式

1.饿汉式单例模式

/**
 * 饿汉式单例模式
 * 线程安全的,但是会造成内存浪费,尤其是在没有真正使用到的情况下,性能上也是浪费。
 */
public class SingletonDemo {

    private SingletonDemo () {}

    private static SingletonDemo singletonDemo = new SingletonDemo();

    public static SingletonDemo getInstance() {
        return singletonDemo;
    }

}
/**
 * 饿汉式单例模式
 * 利用静态代码块来解决
 */
public class SingletonDemo5 {

    private SingletonDemo5() {}
    private static SingletonDemo5 singletonDemo = null;

    static {
        singletonDemo = new SingletonDemo5();
    }

    public static SingletonDemo5 getInstance() {
        return singletonDemo;
    }

    public static void main(String[] args) {
        System.out.println(SingletonDemo5.getInstance());
        System.out.println(SingletonDemo5.getInstance());
    }

}

2.懒汉式单例

/**
 * 懒汉式单例模式
 * 线程不安全的,比起饿汉式性能资源上更有优势。
 */
public class SingletonDemo1 {

    private SingletonDemo1() {}

    private static SingletonDemo1 singletonDemo = null;

    public static SingletonDemo1 getInstance() {
        /**
         * 线程不安全出现在下面的if代码块
         * Thread_A 和 Thread_B同时到达if的时候,就会出现两个对象实例。
         */
        if(null == singletonDemo){
            singletonDemo = new SingletonDemo1();
        }
        return singletonDemo;
    }
}

下面就进行修改,让它成为线程安全的!
变型一:

/**
 * 懒汉式单例模式
 * 线程安全的,比起饿汉式性能资源上更有优势。
 */
public class SingletonDemo2 {

    private SingletonDemo2() {}

    private static SingletonDemo2 singletonDemo = null;

    /**
     * synchronized 只会让一个线程进入创建对象实例。但是
     *  会造成性能问题。
     * @return
     */
    public synchronized static SingletonDemo2 getInstance() {

        if(null == singletonDemo){
            singletonDemo = new SingletonDemo2();
        }
        return singletonDemo;
    }
}

变型二:

/**
 * 懒汉式单例模式
 * 线程不安全的,比起饿汉式性能资源上更有优势。
 */
public class SingletonDemo3 {

    private SingletonDemo3() {}

    private static SingletonDemo3 singletonDemo = null;

    /**
     * synchronized 下沉到方法内部,这种形式也可以叫做:
     * 双重检测同步机制
     * 这样同样会有问题:造成的原因是指令重排序
     *
     * 创建对象简单过程:
     *  1.分配对象内存空间
     *  2.引用指向刚才分配的内存空间
     *  3.初始化对象
     *
     *  指令重排序会让:2、3进行颠倒
     *
     *
     * @return
     */
    public synchronized static SingletonDemo3 getInstance() {

        if(null == singletonDemo){   // 线程A  如果是132的过程B->3,A在此处就会直接返回未完成初始化的对象实例
            synchronized (SingletonDemo.class) {
                if (null == singletonDemo) {
                    singletonDemo = new SingletonDemo3(); // 线程B - 1【3】2执行到第三步
                }
            }
        }
        return singletonDemo;
    }
}

针对变型二里面出现的问题,这个时候就要上volatile 这个杀器了,他可以让程序屏蔽指令重排序:

/**
 * @author Kevin 
 * 
 * 单例设计模式
 *
 */
public class SingletonDemo {
	private SingletonDemo(){
		//不可实例化
	}
	/**
	 * volatile保持可见性
	 */
	private volatile static SingletonDemo singleton;
	
	/**
	 * @return SingletonDemo
	 * 
	 * 此方法再指令重排序时候,不能保证安全单例,所以使用volatile。
	 * 
	 */
	public static SingletonDemo getInstance(){
		if(singleton == null){
			synchronized (SingletonDemo.class) {
				if(singleton == null){
					singleton = new SingletonDemo();
				}
			}
		}
		return singleton;
	}

}

3.利用枚举类的单例写法(推荐)

public class SingletonEnumDemo {
    private SingletonEnumDemo() {}

    public synchronized static SingletonEnumDemo getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton {
        INSTANCE;
        private SingletonEnumDemo singletonDemo = null;

        // JVM保证该方法只会被调用一次,绝对安全
        Singleton () {
            singletonDemo = new SingletonEnumDemo();
        }

        public SingletonEnumDemo getInstance () {
            return singletonDemo;
        }
    }
}
原文地址:https://www.cnblogs.com/Kevin-1992/p/12608430.html