单例模式的几种用法

单例模式的几种用法

1、饿汉式单例

package com.singleton;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 13:04
 * @description: 饿汉式单例 缺点:内存浪费
 */
public class HungrySingleton {

    private static HungrySingleton hungrySingleton = new HungrySingleton();

    /*static {
        hungrySingle = new HungrySingle();
    }*/

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}

2、懒汉式单例

package com.singleton;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 13:07
 * @description: 懒汉式单例 缺点:synchronized 性能问题
 */
public class LazySingleton {

    private static LazySingleton lazySingleton = null;

    private LazySingleton(){}

    /**
     * 原始
     * @return
     */
    public static synchronized LazySingleton getInstance(){
        if(lazySingleton ==null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

    /**
     * 双重校验优化后的方法
     * lazySingleton属性要加上volatile关键字修饰
     * @return
     */
    public static LazySingleton getInstance2(){
        if(lazySingleton ==null){
            synchronized (LazySingleton.class){
                if(lazySingleton ==null) {
                    lazySingleton = new LazySingleton();
                }
            }

        }
        return lazySingleton;
    }
}

3、静态内部类的方式

package com.singleton;

import java.io.Serializable;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 13:16
 * @description: 使用内部类 调用getInstance方法时返回一定会先加载内部类 优点:兼顾饿汉式内存浪费 以及synchronized性能问题
 */
public class InnerClassSingleton implements Serializable {

    public static final InnerClassSingleton getInstance(){
        return InnerClass.LAZY;
    }

    private InnerClassSingleton(){
        // 防止反射破化单例
        if(InnerClass.LAZY != null){
            throw new RuntimeException("不可反射创建");
        }
    }

    /**
     * 防止序列化破坏单例 加上这个方法private Object readResolve()
     * readResolve()方法底层还是创建了新的对象,只是新对象没有被返回还是会产生内存分配的问题
     *
     * @return
     */
    private Object readResolve(){
        return InnerClass.LAZY;
    }

    //当前类有引用内部类时一定会先加载内部类
    private static class InnerClass{
        private static final InnerClassSingleton LAZY = new InnerClassSingleton();

    }
}

4、注册式单例(枚举)

package com.singleton;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 16:17
 * @description: 注册式单例 使用优雅,是最推荐的一种写法。
 *              缺点:但是跟饿汉式单例一样,在类加载时就会将对象初始化,不适合创建大量单例对象的场景
 */
public enum EnumSingleton {

    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

5、容器式单例

package com.singleton;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 16:44
 * @description: 容器式单例 类似于Spring ioc
 */
public class ContainerSingleton {

    private ContainerSingleton(){}

    private static Map<String,Object> ioc = new ConcurrentHashMap<>();

    public static Object getBean(String className) {
        synchronized (ioc) {
            if (!ioc.containsKey(className)) {
                try {
                    Class<?> clazz = Class.forName(className);
                    Object obj = clazz.newInstance();
                    ioc.put(className, obj);
                    return obj;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return ioc.get(className);
    }
}


6、ThreadLocal实现线程单例

package com.singleton;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 17:02
 * @description: 线程单例
 * ThreadLocal不能保证其创建的对象式全局唯一的,但是能保证在单个线程中是唯一的,天生是线程安全的
 */
public class ThreadLocalSingleton {

    private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
            new ThreadLocal<ThreadLocalSingleton>() {
                @Override
                protected ThreadLocalSingleton initialValue() {
                    return new ThreadLocalSingleton();
                }
            };

    private ThreadLocalSingleton() {}

    public static ThreadLocalSingleton getInstance() {
        return threadLocalInstance.get();
    }
}

测试代码:

package com.singleton;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @author: RenKaiQi
 * @date: 2021/4/6 15:37
 * @description:
 */
public class SingletonTest {

    public static void main(String[] args) {
        // 反射破坏单例
        /*Class<InnerClassSingle> clazz = InnerClassSingle.class;
        try {
            Constructor<InnerClassSingle> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            InnerClassSingle innerClassSingle1 = constructor.newInstance();
            System.out.println(innerClassSingle1);
            InnerClassSingle innerClassSingle2 = constructor.newInstance();

            System.out.println(innerClassSingle2);
        } catch (Exception e) {
            e.printStackTrace();
        }*/

        // 序列化破坏单例
        /*InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
        InnerClassSingleton instance2 = null;
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("InnerClassSingle.obj");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(instance1);
            objectOutputStream.flush();
            objectOutputStream.close();

            FileInputStream fileInputStream = new FileInputStream("InnerClassSingle.obj");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            instance2 = (InnerClassSingleton) objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(instance1);
        System.out.println(instance2);*/

        // 注册式单例测试
        EnumSingleton enumSingleton1 = EnumSingleton.getInstance();
        enumSingleton1.setData(new Object());
        EnumSingleton enumSingleton2 = null;
        EnumSingleton enumSingleton3 = EnumSingleton.getInstance();
        enumSingleton3.setData(new Object());
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("Object.obj");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(enumSingleton1);

            FileInputStream fileInputStream = new FileInputStream("Object.obj");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            enumSingleton2 = (EnumSingleton) objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(enumSingleton1 == enumSingleton2); // true
        System.out.println(enumSingleton1 == enumSingleton3); // true
        System.out.println(enumSingleton2 == enumSingleton3); // true
    }



}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值