单例模式

1.懒汉模式

package org.example.base.test;

/**
 * @author l
 * @date Created in 2021/4/13 14:20
 *所谓懒汉模式,就是太懒了。懒得先创建好实例。只有需要的时候,才去判断是否有实例,没有才去创建。
 */
public class Singleton {
    private static Singleton singleton;

    /**
     * @date 14:44 2021/4/13
     * 构造方法私有化
     **/
    private Singleton() {
    }

    public static Singleton getInstance() {
        /**
         * @date 14:41 2021/4/13
         * 这个地方存在线程安全问题。当有多个线程同时执行到这个哩。会创建多个实例。就不是单例模式了。
         **/
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }

}

2.懒汉模式,双重检验锁实现。

package org.example.base.test;

/**
 * @author l
 * @date Created in 2021/4/13 14:20
 * 懒汉模式 -> 双重检验锁
 */
public class Singleton {

    /**
     * @date 15:13 2021/4/13
     * 这里使用volatile关键字是因为volatile能保证共享变量对多个线程是可见的。既保证了可见性。
     * 同时它还能禁止指令重排序。既保证了有序性。
     **/
    private volatile static Singleton singleton;

    /**
     * @date 14:44 2021/4/13
     * 构造方法私有化
     **/
    private Singleton() {
    }

    public static Singleton getInstance() {
        //第一次检验,一旦实例化完成,以后就减少获取和释放锁的开销
        if (singleton == null) {
            synchronized (Singleton.class) {
                //第二次检验
                if (singleton == null) {
                    /**
                     * 这里的new操作,并不是原子性操作
                     * 创建一个对象实例可以分为三步
                     * 1.为对象分配内存空间
                     * 2.调用构造函数初始化
                     * 3.把对象引用赋值给变量
                     *这里2 3 步有可能发生指令重排序。
                     *当线程一按照132执行,执行到3时,线程二刚好执行到判断,并且判断不为null,从而访问一个未初始化的对象,报异常。
                     * 因而使用volatile关键字修饰变量,保证变量对所有线程都是可见的。同时禁止指令重排序。
                     **/
                    singleton = new Singleton();
                }

            }
        }
        return singleton;
    }

}

3.懒汉模式,静态内部类实现

package org.example.base.test;

/**
 * @author l
 * @date Created in 2021/4/13 14:20
 * 懒汉模式 -> 静态内部类
 */
public class Singleton {

    private Singleton() {
    }

    /**
     * 静态内部类。外部类加载的时候并不会立即加载内部类,所以是懒汉式。
     * 只有第一次调用getInstance方法时才会加载内部类,初始化Singleton实例。
     * 同时,内部类SingletonInner初始化过程中是线程安全的。
     */
    private static class SingletonInner {
        private static final Singleton singleton = new Singleton();
    }

    public Singleton getInstance() {
        return SingletonInner.singleton;
    }


}

4.枚举单例

package org.example.base.test;

/**
 * @author l
 * @date Created in 2021/4/13 14:20
 * 单例模式->枚举单例
 * 在第一次使用枚举类的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
 * 所以枚举实例创建是线程安全的,在任何情况下,它都是一个单例
 */
public enum Singleton {

    ONE(1,"1"),TWO(2,"2"),THREE(3,"3");

    private Integer num;
    private String str;

   Singleton(Integer num, String str) {
        this.num = num;
        this.str = str;
    }

    @Override
    public String toString() {
        return "Singleton{" +
                "num=" + num +
                ", str='" + str + '\'' +
                '}';
    }

    public static void main(String[] args) {
        System.out.println(Singleton.ONE);
    }

}

5.饿汉模式

package org.example.base.test;

/**
 * @author l
 * @date Created in 2021/4/13 14:20
 * 饿汉模式
 */
public class Singleton {
    /**
     * private 修饰变量保证了其私有性,不可见,不可访问。
     * static  修饰变量保证了该变量引用不依赖于类的对象进行访问,它当且仅当在类初次加载时会被初始化,可以通过类名访问。
     * 同时也不会被GC垃圾回收器给回收掉
     * final 修饰变量,保证其引用不可更改
     **/
    private static final Singleton singleton = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return singleton;
    }


}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值