设计模式 单例模式

一、使用场景

  系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。

二、单例模式实现的要点:

  1、私有、静态的单例对象

  2、构造函数私有化

  3、提供对外的公共访问方法,以获得单例对象

三、单例模式有三种实现

  1、饱汉式(用的时候实例化)

public class SingletonDemo {
    // 有的会加final修饰符(更为严谨),添加final修饰符之后,指向的引用不能再做更改。
    // 这是final的用法:final成员变量表示常量,只能被赋值一次,赋值后值不能再改变。
    private static final SingletonDemo singletonInstance = new SingletonDemo();

    private SingletonDemo() {  
    }

    public static SingletonDemo getSingletonInstance() {
        return singletonInstance;
    }
}

  

  2、饿汉式(初始化已准备好)

public class SingletonDemo {
    // 这个就不能加final,因为要在其他地方给他再次赋值呢。
    // 加了final,那就默认一直是null啦,而且还不能再次给此属性赋值。
    // 此属性是静态,那么就是共享数据,多线程并发操作共享数据是有可能的。那么就会出现下面的线程不安全现象。
    private static SingletonDemo singletonInstance;

    private SingletonDemo() {
    }

    public static SingletonDemo getSingletonInstance() {
        if (singletonInstance == null) {
            // 在这个地方,多线程的时候,
            // 可能A线程挂起,此属性还是null,那么B线程可能也判断条件OK也进来啦。
            // 然后A线程可以执行的时候就会new个对象,线程B也会new个对象。
            // 就不能保证内存的唯一性。也就是线程不安全
            singletonInstance = new SingletonDemo();
        }
        return singletonInstance;
    }

    /// **
    // * 为了应对上述的不安全,可以简单的如下操作给方法添加[synchronized],使之成为同步函数。
    // * 但是:
    // * 在很多线程的情况下,就每个线程访问都得判断锁,效率就是问题。所以,才有后面的[双重锁形式]
    // */
    // public static synchronized SingletonPattern2 getSingletonInstance() {
    // if (singletonInstance == null) {
    // singletonInstance = new SingletonPattern2();
    // }
    // return singletonInstance;
    // }
}

  3、双重锁

/**
 * 双重锁形式
 * 这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,
 * 只有第一次才同步,创建了以后就没必要了。避免土豪模式下创建单例,可能存在的线程不安全问题。
 * <p>
 * Created by lxk on 2017/3/23
 */
public class SingletonDemo {
    
    private static SingletonDemo singletonInstance;

    private SingletonDemo() {
    }

    /**
     * 静态方法同步的时候,使用的锁,就不能是this,而是类.class
     */
    public static SingletonDemo getSingletonInstance() {
        if (singletonInstance == null) {
            // 这个地方可能有多个线程,在这排队,ABCD..。
            synchronized (SingletonDemo.class) {
                if (singletonInstance == null) {
                    // 假设第一次A线程走到这,然后,呈挂起状态。这个时候,单例对象还未创建;
                    // 假设此时,B线程也来了判断单例对象==null成立,但是,因为A线程已经给里层的if判断上锁,所以,B只能在外等着。
                    // 假设A线程被唤醒,那么,单例就会下面语句赋值,单例对象就创建啦。然后释放锁。B就可以进来啦。
                    // B线程进来之后,先判断单例对象是否为null,发现已经不是null啦,那么就不需要创建啦。
                    // CD线程同样,
                    // 再往后面来的,第一个if就进不来啦,那就不会判断锁了。
                    singletonInstance = new SingletonDemo();
                }
            }
        }
        return singletonInstance;
    }
}

      转载自:http://blog.csdn.net/qq_27093465/article/details/50978916

原文地址:https://www.cnblogs.com/zxguan/p/7825126.html