单例设计模式

单例设计模式

单例模式简单概述

单例模式:
    某些场景,某个类只需要一个实例,
    但是你定义一个类之后,是给别人使用的,你不能保证其他人只创建一个实例,
    所以通过单例模式设计类,就能保证该类在内存中只有一个实例。
常见的单例模式:
    饿汉式:Singleton_lhs
    懒汉式:Singleton_ehs
    
    两者的共同点:
        1.私有构造器,不能通过new关键字实例化
        2.都有一个获取该类实例的公共静态方法
    两者的不同点:
        1.饿汉式在类内部创建类实例时就初始化了
        2.懒汉式在类内部创建类实例时还没初始化,
            而是在调用返回类实例的静态方法内部才初始化。

饿汉式

饿汉式实现步骤:
饿汉式的意思是:只要我被加载进内存,我就迫不及待地初始化该类唯一实例。

1.私有化构造器,不能通过new关键字创建该类对象。
2.在类内部声明该类唯一实例成员,并初始化。
3.声明一个返回该类唯一实例的公共静态方法。
饿汉式实现代码
/**
 *  饿汉式
 */
class Singleton_ehs{
    /**
     *  私有的、静态的、最终的本类实例
     */
    private static final Singleton_ehs SINGLETON_EHS = new Singleton_ehs();

    /**
     *  私有的构造器,不能手动创建对象
     */
    private Singleton_ehs(){}

    /**
     *  返回本类唯一实例的静态公共方法
     * @return
     */
    public static Singleton_ehs getSingletonEhs(){
        return SINGLETON_EHS;
    }
}
饿汉式测试代码
   Singleton_ehs singleton_ehs1 = Singleton_ehs.getSingletonEhs();
   Singleton_ehs singleton_ehs2 = Singleton_ehs.getSingletonEhs();
   System.out.println(singleton_ehs1);
   System.out.println(singleton_ehs2);
   System.out.println(singleton_ehs1==singleton_ehs2);
运行结果
测试代码中,用类名调用静态方法获取该类的两个对象,分别输出各自的地址,
发现是一样的,并比较两个对象在堆内存中的地址,发现也是一样的,
说明了饿汉式实现单例模式成功了。
cn.xxxq.Singleton_ehs@1540e19d
cn.xxxq.Singleton_ehs@1540e19d
true

懒汉式

懒汉式的意思是:我太懒了,就算我被加载进内存了,也只有等你调用了
获取类实例的方法,我才初始化该类唯一的实例。

1.私有构造器,不能通过new关键字创建该类对象。
2.在类内部声明该类唯一的实例,但不初始化。
3.在类内部声明一个公共静态方法,作用是返回该类唯一的实例。
4.懒汉式会产生线程安全问题。
懒汉式线程安全问题
懒汉式是在调用静态方法时才会实例化,所以会产生线程安全问题,下面用代码说明。
/**
 *  懒汉式
 */
class Singleton_lhs {
    /**
     * 私有的、静态的本类实例
     */
    private static Singleton_lhs SINGLETON_LHS;

    /**
     * 私有的构造器,不能手动创建对象
     */
    private Singleton_lhs() {}

    /**
     * 获取该类实例的静态方法
     * 这个方法看似没问题,但是在多线程环境下就有问题了。
     *
     * @return
     */
    public static Singleton_lhs getSingletonLhs() {
        //1.线程1进来,在这里被挂起了。
        //3.然后线程1被唤醒了,因为SINGLETON_LHS还是null,进入if判断里面
        if (SINGLETON_LHS == null) {
            //2.之后线程2进来,在这里被挂起了,此时SINGLETON_LHS还是null
            //4.线程1进来了,创建Singleton_lhs实例
            //6.此时线程2也被唤醒了,因为已经进来if判断里面,所以直接创建Singleton_lhs实例
            SINGLETON_LHS = new Singleton_lhs();
        }
        //5.线程1返回该实例
        //7.线程2也返回实例
        //8.最终线程1和线程2返回该类的实例是不一样的
        return SINGLETON_LHS;
    }
}
由于Java的多线程是抢占式调度,导致了线程执行具有不确定性,
又因为线程执行不确定性,从而导致懒汉式会有线程安全问题。
同步方法解决懒汉式线程安全问题
/**
 *  既然是多线程问题,可以使用同步代码块或者同步方法解决。
 *  同步方法解决,但是同步方法的执行效率比同步代码块低。
 */
public static synchronized Singleton_lhs getSingletonLhs_SyncMethod(){
    if(SINGLETON_LHS==null){
        SINGLETON_LHS = new Singleton_lhs();
    }
    return SINGLETON_LHS;
}
同步代码块解决懒汉式线程安全问题
/**
 *  同步代码块解决懒汉式线程安全问题
 * @return
 */
public static Singleton_lhs getSingletonLhs_Sync(){

    /*
        这样也能解决线程安全问题,但是效率太低,每个线程都要进行等待并判断。
    */
    /*synchronized (Singleton_lhs.class){
        if(SINGLETON_LHS==null){
            SINGLETON_LHS = new Singleton_lhs();
        }
    }*/

    /*
        这样效率就会高些,只进行了一次等待并判断
    */
    if (SINGLETON_LHS == null){
        synchronized (Singleton_lhs.class){
            if(SINGLETON_LHS==null){
                SINGLETON_LHS = new Singleton_lhs();
            }
        }
    }
    return SINGLETON_LHS;
}
懒汉式测试代码
/**
 *  懒汉式
 */
Singleton_lhs singletonLhs1 = Singleton_lhs.getSingletonLhs_Sync();
Singleton_lhs singletonLhs2 = Singleton_lhs.getSingletonLhs_Sync();
System.out.println(singletonLhs1);
System.out.println(singletonLhs2);
System.out.println(singletonLhs1==singletonLhs2);
运行结果
运行结果说明了,同步代码块已经解决了线程安全问题。
cn.xxxq.Singleton_lhs@677327b6
cn.xxxq.Singleton_lhs@677327b6
true
单例模式总结
上面内容就是我对单例模式的见解,大家如果有不同的想法思路,可以提出来一起交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值