设计模式-单例模式

        单例模式是常见的一种设计模式,通过单例模式创建的类在当前进程中只有一个实例。

        Java中单例模式的定义:“一个类有且只有一个实例,并且自行实例化向整个系统提供。”

1.单例模式的特点

        1)单例类只能有一个实例;

        2)单例类自行创建唯一实例;

        3)单例类须向所有其他对象提供该实例。

2. 常见实现方法

        1. 饿汉式-线程安全

        优点:简单,不存在线程安全问题。

        缺点:浪费资源(未调用时也会创建出实例)。

//饿汉式
public class HungryMan {
    //初始化
    private static HungryMan instance = new HungryMan();
    //私有化构造方法
    private HungryMan(){}
    //向外提供方法获取实例
    public static HungryMan getInstance(){
        return instance;
    }   
}

        2. 懒汉式-非线程安全

        优点:解决了浪费资源的问题,在调用时才创建出实例。

        缺点:非线程安全。

//懒汉式-非线程安全
class LazyMan{
    private static LazyMan instance;
    private LazyMan(){}
    public static LazyMan getInstance(){
        if(instance == null) {
            instance = new LazyMan();
        }
        return instance;
    }
}

        3. 懒汉式-线程安全

        优点:线程安全

        缺点:效率低,多线程模式下线程只能一个个访问getInstance方法。

//懒汉式-线程安全
class LazyMan{
    private static LazyMan instance;
    private LazyMan(){}
    public synchronized static LazyMan getInstance(){
        if(instance == null) {
            instance = new LazyMan();
        }
        return instance;
    }
}

        4. 双重验证

        优点:该模式在多线程环境下仍能保持高性能。

        缺点:并非绝对安全,可以通过反射来破坏。

//双重校验
class LazyMan {
    /** 为什么要使用valatile关键字?
     *  instance = new LazyMan(); 可以拆解为三步
     *  1. 分配内存
     *  2. 初始化对象
     *  3. 指向刚分配的地址
     *  假设 A 线程执行了1和3,还未执行2,此时B线程来判断NULL,B就会返回还未初始化的instance。
     */
    private volatile static LazyMan instance;
    private LazyMan() {
    }
    public static LazyMan getInstance() {
        //首次判空,目的是提高效率,如果instance不为空则直接返回,不需要去获取锁
        if (instance == null) {
            //加锁,防止多线程同时创建实例
            synchronized (LazyMan.class) {
                //二次判空,防止等待锁的线程重复创建实例
                if (instance == null)
                    instance = new LazyMan();
            }
        }
        return instance;
    }
}

        如何防止反射破坏该模式?

        只需在该类的内部添加方法来阻止序列化生成新的对象。

class LazyMan implements Serializable {
    private volatile static LazyMan instance;
    private LazyMan() {
    }
    public static LazyMan getInstance() {
        if (instance == null) {
            synchronized (LazyMan.class) {
                if (instance == null)
                    instance = new LazyMan();
            }
        }
        return instance;
    }

    private Object readResolve(){
        //防止序列化生成新的实例
        return instance;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值