单例模式demo(懒汉式+饿汉式)

饿汉式

public class SingletonTest1 {
    public static void main(String[] args) {
        Bank b1 = Bank.getInstance();
        Bank b2 = Bank.getInstance();
        System.out.println(b1 == b2);
    }
}

class Bank{//饿汉式
    //1.私有化类的构造器
    private Bank(){}
    //2.内部创建类对象,需要是静态、私有的
    private static Bank instance = new Bank();
    //3.公共的静态方法  返回类对象
    public static Bank getInstance(){
        return instance;
    }
}

懒汉式- 基础版

public class SingletonTest2 {
    public static void main(String[] args) {
        Order o1 = Order.getInstance();
        Order o2 = Order.getInstance();
        System.out.println(o1 == o2);
    }
}

class Order{//懒汉式-基础版,线程不安全
    //1.私有化构造方法
    private Order() {}
    //2.内部声明类对象,但未初始化;需要是静态、私有的
    private static Order instance = null;
    //3.公共静态方法,若第一次调用,需要初始化对象;否则直接返回
    public static Order getInstance(){
        if(instance == null){
            instance = new Order();
        }
        return instance;
    }
}

懒汉式 - 改进版(同步方法)

public class SingletonTest2 {
    public static void main(String[] args) {
        Order1 o1 = Order1.getInstance();
        Order1 o2 = Order1.getInstance();
        System.out.println(o1 == o2);
    }
}
class Order1{//懒汉式-改进版,线程安全,对getInstance()加了锁的处理,
    // 保证了同一时刻只能有一个线程访问并获得实例,
    // 但是缺点也很明显,因为synchronized是修饰整个方法,
    // 每个线程访问都要进行同步,而其实这个方法只执行一次实例化代码
    // 就够了,每次都同步方法显然效率低下
    private Order1() {}
    private static Order1 instance = null;
    //用synchronized锁住整个方法
    public static synchronized Order1 getInstance(){
        if(instance == null){
            instance = new Order1();
        }
        return instance;
    }
}

懒汉式 - 双重检测

//1.使用私有的构造函数,确保正常情况下该类不能被外部初始化(非正常情况比如通过反射初始化,一般使用反射之后单例模式也就失去效果了)。
//2.getInstance方法中第一个判空条件,逻辑上是可以去除的,去除之后并不影响单例的正确性,但是去除之后效率低。
// 因为去掉之后,不管instance是否已经初始化,都会进行synchronized操作,而synchronized是一个重操作消耗性能。加上之后,如果已经初始化直接返回结果,不会进行synchronized操作。
//3.加上synchronized是为了防止多个线程同时调用getInstance方法时,各初始化instance一遍的并发问题。
//4.getInstance方法中的第二个判空条件是不可以去除,如果去除了,并且刚好有两个线程a和b都通过了第一个判空条件。
// 此时假设a先获得锁,进入synchronized的代码块,初始化instance,a释放锁。接着b获得锁,进入synchronized的代码块,也直接初始化instance,instance被初始化多遍不符合单例模式的要求~。
// 加上第二个判空条件之后,b获得锁进入synchronized的代码块,此时instance不为空,不执行初始化操作。
//5.instance的声明有一个voliate关键字,如果不用该关键字,有可能会出现异常。因为instance = new Test();并不是一个原子操作,会被编译成三条指令,如下所示。
//5.1 给Test的实例分配内存 5.2 初始化Test的构造器 5.3 将instance对象指向分配的内存空间(注意 此时instance就不为空)
//然后咧,java会指令重排序,JVM根据处理器的特性,充分利用多级缓存,多核等进行适当的指令重排序,使程序在保证业务运行的同时,充分利用CPU的执行特点,最大的发挥机器的性能!
// 简单来说就是jvm执行上面三条指令的时候,不一定是1-2-3这样执行,有可能是1-3-2这样执行。
// 如果jvm是按照1-3-2来执行的话,当1-3执行完2还没执行的时候,如果另外一个线程调用getInstance(),因为3执行了此时instance不为空,直接返回instance。
// 问题是2还没执行,此时instance相当于什么都没有,肯定是有问题的。然后咧,voliate有一个特性就是禁止指令重排序,上面的三条指令是按照1-2-3执行的,这样就没有问题了。
public class SingletonTest2 {
    public static void main(String[] args) {
        Order2 o1 = Order2.getInstance();
        Order2 o2 = Order2.getInstance();
        System.out.println(o1 == o2);
    }
}
class Order2{//懒汉式-高级版,双重检查懒汉式。
    private Order2() {}
    //volatile修饰实例,保证可见性
    private static volatile Order2 instance = null;
    //为什么要做两次判断呢?这是为了线程安全考虑,还是那个场景,对象还没实例化,两个线程A和B同时访问静态方法并同时运行到第一个if判断语句,
    // 这时线程A先进入同步代码块中实例化对象,结束之后线程B也进入同步代码块,如果没有第二个if判断语句,那么线程B拿到锁之后,也同样会执行实例化对象的操作。
    public static Order2 getInstance(){
        if(instance == null){
            //不再锁整个方法,只锁初始化的代码块
            synchronized (Order2.class){
                if(instance == null){
                    instance = new Order2();
                }
            }
        }
        return instance;
    }
}

懒汉式 - 静态内部类

public class SingletonTest2 {
    public static void main(String[] args) {
        Order3 o1 = Order3.getInstance();
        Order3 o2 = Order3.getInstance();
        System.out.println(o1 == o2);
    }
}
class Order3{//懒汉式-终级版,通过静态内部类实现
    private Order3(){}
    //静态内部类方式在Order3类被加载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会加载Order3Instance类,从而完成对象的实例化
    //类的静态属性只会在第一次加载类的时候初始化,也就保证了Order3Instance中的对象只会被实例化一次,并且这个过程也是线程安全的。
    private static class Order3Instance{
        private static final Order3 instance = new Order3();
    }
    public static Order3 getInstance(){
        return Order3Instance.instance;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值