Fork me on GitHub

Java 之单例设计模式

设计模式: 对问题行之有效的解决方式, 其实它是一种思想.

单例设计模式

解决的问题:就是可以保证一个类在内存中的对象唯一性. 即单个实例.

比如对于A 和 B 两个程序使用同一个配置信息对象时, A 对配置信息作出修改, B 也与之对应的更新配置信息, 即需要保证该对象的唯一性.

如何保证对象唯一性呢?
  1. 不允许其他程序用 new 创建该类对象
  2. 在该类中创建一个本类实例
  3. 对外提供一个方法让其他程序可以获取该对象.
步骤:
  1. 私有化该类构造函数
  2. 通过 new 在本类中创建一个本类对象
  3. 定义一个公有方法, 将创建的对象返回
两种方式
  1. 饿汉式: 类一加载, 对象就存在了.
  2. 懒汉式: 类加载进来, 没有对象, 只有调用 getInstance 方法时, 才会创建对象.
    也称为 单例设计模式的延迟加载模式. 但是, 懒汉式在多线程访问时,存在安全隐患.
// 第一种方式: 饿汉式
class Single
{
    Single s = new Single(); // 在本类中创建一个本类对象

    private Single(){} // 私有化该类构造函数

    // 定义一个公有方法, 将创建的对象返回. 用于返回对象 s, 所以返回类型 Single
    public Single getInstance()
    {
        return s;
    }
}

class SingleDemo
{
    public static void main(String[] args)
    {
        Single ss = Single.getInstance();
    }
}

/*
分析一: main 函数中, getInstance 方法调用不能使用对象调用, 只能使用类名调用.
       所以 Single 类中该方法需要使用 static 修饰.
分析二: getInstance 方法为静态方法, 它访问的内容必须是静态的,所以对象 s 也需要静态修饰.
*/
// 改进
class Single
{
    private static Single s = new Single();

    private Single(){}

    public static Single getInstance() // 提供该方法访问实例对象 s, 是为了对象的可控
    {
        return s;
    }
}

class SingleDemo
{
    public static void main(String[] args)
    {
        Single ss = Single.getInstance();
    }
}

// 第二种方式: 懒汉式
// 类加载进来, 没有对象, 只有调用 getInstance 方法时, 才会创建对象.
class Single2
{
    private static Single2 s = null;

    private Single(){}

    public static Single2 getInstance()
    {
        if(s==null)
            s = new Single2();
        return s;
}
}
// 示例:下列代码的输出结果
class SingleDemo
{
    public static void main(String[] args)
    {
        Test t1 = Test.getInstance();
        Test t2 = Test.getInstance();
        t1.setNum(10);
        t2.setNum(20);
        System.out.println(t1.getNum()); // 输出 20
        System.out.println(t2.getNum()); // 输出 20
}
}

class Test
{
    private int num;

    private static Test t = new Test();
    private Test(){}
    public static Test getInstance()
    {
        return t;
    }

    public void setNum(int num)
    {
        this.num = num;
    }

    public int getNum()
    {
        return num;
    }
}

// 懒汉式二:避免多线程同时调用getInstance()方法, 可以使用关键字synchronized
class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton(){}

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

// 懒汉式三:为提高系统性能,对"instance = new LazySingleton()"进行锁定
class LazySingleton{
    private static LazySingleton instance = null;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(instance == null){                   // 此处,有可能造成单例对象不唯一
            synchronized(LazySingleton.class){
                instance = new LazySingleton();
            }
        }
        return instance;
    }
}

// 懒汉式四:双重检查锁定(Double-Check Locking)
class LazySingleton{
    // 注意,此处增加修饰符 volatile
    private volatile static LazySingleton instance = null;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        // 第一重判断
        if(instance == null){
            // 锁定代码块
            synchronized(LazySingleton.class){
                // 第二重判断
                if(instance == null){
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

//单例第三种方式: Initialization Demand Holder(IoDH)技术
// 在单例类中增加一个静态(static)内部类
class Singleton{
    private Singleton(){}

    // 静态类
    private static class HolderClass {
        private final static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return HolderClass.instance;
    }

    public static void main(String args[]){
        Singleton s1, s2;
        s1 = Singleton.getInstance();
        s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }
}



_参考资料_ - [JavaSE 基础视频(毕向东)](https://www.bilibili.com/video/av3092292/#page=4) - [单例模式中的双重检查](http://blog.csdn.net/chenchaofuck1/article/details/51702129)
posted @ 2017-08-27 09:57  小a的软件思考  阅读(206)  评论(0)    收藏  举报