设计模式之单例模式(Java)

单例模式

问题

多线程操作同一对象保证对象的一致性

解决思路

只有一次实例化过程,产生一个实例化对象,并提供返回该对象的方法。

单例模式的分类

1 饿汉式

在加载类的时候就产生实例对象

public class HungerySingleton {

    /**
     * 在加载说就产生了实例对象
     */
    private static HungerySingleton instance = new HungerySingleton();

    private HungerySingleton(){

    }
    /**
     * @return 返回实例对象
     */
    public static HungerySingleton getInstance(){
        return instance;
    }
}

线程安全性:在加载时就已经实例化,所以只有一次实例化,线程是安全的。

不是懒加载

性能不好

2 懒汉式

在加载类时不声明实例对象,当使用该对象时才会实例化对象,不过对象也只能实例化一次。

public class HoonSinglenton {
    /**
     * 在加载时只声明变量不产生了实例对象
     */
    private static HoonSinglenton instance = null;
    private HoonSinglenton(){

    }
    /**
     * @return 返回实例对象
     */
    public static HoonSinglenton getInstance(){
        if (instance == null){
            instance = new HoonSinglenton();
        }
        return instance;
    }
}

**线程安全性:不安全,不能保证实例对象的唯一性。**在多线程访问时,如果有两个线程同时进入if判断那么这两个线程获取的对象不是同一对象,不符合单例模式的定义。

是懒加载

性能好

3 懒汉式+同步方法

public class HoonSynSinglenton {

    private static HoonSynSinglenton instance = null;
    private HoonSynSinglenton(){

    }

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

线程安全性:安全

是懒加载

性能不好:synchronized修饰的方法在多线程访问时会退化成串行执行。

4 DCL(Double-Check-Locking)

public class DCL {

    private static DCL instance = null;
    private DCL(){

    }

    public synchronized static DCL getInstance(){
        if (instance == null){
            synchronized(DCL.class){
                if (instance == null){
                    instance = new DCL();
                }
            }
        }
        return instance;
    }
}

性能比较好

懒加载

保证线程安全性

缺点:会因为指令重排序,引起空指针异常

5 volatile + DCL

private volatile static DCL instance = null;

DCL解决方案

6 Holder

使用比较广泛的一种单例模式

在声明类时,成员变量中不声明实例变量,而放到内部静态类中,在静态类中实例化,避免懒汉式中加锁的问题。

public class HolderSinglenton {
    
    private HolderSinglenton(){}
    
    private static class Holder{
        private static HolderSinglenton instance = new HolderSinglenton();
    }
    
    public static HolderSinglenton getInstance(){
        return Holder.instance;
    }
}

7 枚举

Effective Java推荐该方法

public class EnumSingletonDemo {

    private EnumSingletonDemo(){}

    private enum EnumHolder{
        /**
         * 单例对象
         */
        INSTANCE;
        private EnumSingletonDemo instance;
        EnumHolder(){
            this.instance = new EnumSingletonDemo();
        }
        private EnumSingletonDemo getInstance(){
            return instance;
        }
    }
    
    public static EnumSingletonDemo getInstance(){
        return EnumHolder.INSTANCE.getInstance();
    }
}

代码中的的枚举类型是一个内部类,内部类在Java中使用是懒加载只有使用时才会加载。加载EnumSingletonDemo类不会引起内部类的加载。

posted @ 2019-10-02 19:48  紫月冰凌  阅读(369)  评论(0编辑  收藏  举报