单例模式

学习笔记

23种设计模式:

创建型模式(5):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式

结构性模式(7):适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式

行为型模式(11):策略模式,观察者模式,模板方法模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式

问:

为什么要使用单例模式

单例存在哪些问题

单例与静态类的区别

有何替代的解决方案

要实现一个单例模式需要关注几个点:

1.构造器需要是private访问权限的,避免外部new对象。

2.考虑对象创建时的线程安全问题。

3.考虑是否支持延迟加载

4.考虑getInstance()性能是否高(是否加锁)。

单例设计模式:理解起来就是,一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫做单例设计模式,简称单例模式。

对象锁,对同一个对象的执行有效,不同对象的执行是无效的,加锁必须是多个线程共用一把锁才会起作用。

类锁,让所有对象共享一把锁。避免了不同对象之间同时调用函数,导致线程并发问题。实现如下

public class IdGenerator {

    private static final IdGenerator instance = new IdGenerator();

    private AtomicLong id = new AtomicLong();

    private IdGenerator(){
    }

    /**
     * @Description:类加载的时候就完成了初始化
     */
    public static IdGenerator getInstance() {
        return instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}

单例模式:

public class IdGeneratorError {
    
    private static AtomicLong id = new AtomicLong();
    
    public long getId() {
        return id.incrementAndGet();
    }
}

业务概念上来说,如果有些数据在系统中只应保存一份,那就比较适合单例模式。比如配置信息类。

 

1.饿汉式:

饿汉式实现方式,在类加载时,instance静态实例就已经创建并初始化好了,所以,instance实例的创建过程是线程安全的。不过这样的方式不支持延时加载(真正用到时,再创建实例)。

2.懒汉式

支持延时加载,不过加了synchronized,导致并发度低,频繁调用有性能瓶颈。


public class IdGeneratorLazy {

    private AtomicLong id = new AtomicLong();

    private static IdGeneratorLazy instance = null;

    private IdGeneratorLazy() {

    }

    /**
     * @Description:懒汉模式的缺点就是要在getInstance方法上加个锁,导致并发度低。
     * 如果这个方法被频繁调用,那么频繁的加锁和释放锁以及并发度低会造成性能瓶颈。
     */
    public static synchronized IdGeneratorLazy getInstance() {
        if (instance == null) {
            instance = new IdGeneratorLazy();
        }
        return instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}

3.双重检测

支持延时加载和高并发。方式一:

public class IdGenetatorDoubleTest {

    private static AtomicLong id = new AtomicLong();

    private static volatile IdGenetatorDoubleTest instance;

    private IdGenetatorDoubleTest(){

    }

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

    public long getId() {
        return id.incrementAndGet();
    }

}

方式二:

public class IdGenetatorDoubleTest {

    private static AtomicLong id = new AtomicLong();

    private static volatile IdGenetatorDoubleTest instance;

    private IdGenetatorDoubleTest(){

    }

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

    public long getId() {
        return id.incrementAndGet();
    }

}

4.静态内部类

当外部类被加载时,内部类并不会被加载,只有当调用getInstance方法时,内部类才会被调用。instance的线程安全和唯一性由JVM保证,所以这种方式的单例,保证了线程安全,又做到延时加载。这一部分有待深入探究

public class IdGeneratorInnerClass {

    private AtomicLong id = new AtomicLong();

    private IdGeneratorInnerClass(){

    }

    private static class SingletonHolder {
        private static final IdGeneratorInnerClass instance = new IdGeneratorInnerClass();
    }

    public static IdGeneratorInnerClass getInstance() {
        return SingletonHolder.instance;
    }

    public long getId() {
        return id.incrementAndGet();
    }
}

5.枚举

怎么形容呢,就是有点懵逼

public enum  IdGeneratorEnum {

    ;
    private AtomicLong id = new AtomicLong();

    public long getId() {
        return id.incrementAndGet();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值