Java 单例设计模式 常见4种

适合功能

  • 配置文件读写对象, 数据库连接池, Spring的 IOC容器 ApplicationContext, Windows的任务管理/回收站等

主要特点

  1. 单例类只能实例化一次
  2. 提供唯一全局访问入口来获取该实例

饿汉式单例 Eager loading(立即加载方式)

  1. 项目启动, 类加载同时进行实例化对象
  2. 饿汉式单例是线程安全的

public class EagerSingleton implements Serializable {
    private static final long serialVersionUID = 7073777279565036708L;

    private static volatile EagerSingleton instance = new EagerSingleton();

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private EagerSingleton() {
        if(instance != null){
            throw new RuntimeException("不允许被反射实例化");
        }
    }

    public static EagerSingleton getInstance() {
        return instance;
    }

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EagerSingleton > " + Thread.currentThread().getName() + " > " + EagerSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EagerSingleton > Thread-0 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-1 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-2 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-3 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-4 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-5 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-6 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-7 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-8 > com.test.web4.singleton.EagerSingleton@6a3289ca
EagerSingleton > Thread-9 > com.test.web4.singleton.EagerSingleton@6a3289ca

懒汉式单例 Lazy Loading(延迟加载方式)

  • 通过单例内部静态方法, 获取对象或实例化首个实例后获取对象
  • 注: 懒汉式由于有线程安全问题必须做双重检查并加锁
  • *静态变量的赋值操作是由JVM来保证线程安全的

public final class LazySingleton implements Serializable {
    private static final long serialVersionUID = -5683703520820349246L;

    private static volatile LazySingleton instance = null;

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private LazySingleton() {
        if (instance != null) {
            throw new RuntimeException("不允许被反射实例化");
        }
    }

    public static LazySingleton getInstance() {
        if (instance == null) { // 双重检查
            synchronized (LazySingleton.class) {
				if(instance == null) { // 双重检查
					instance = new LazySingleton();
				}
            }
        }
        return instance;
    }

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("LazySingleton > " + Thread.currentThread().getName() + " > " + LazySingleton.getInstance());
            });
            thread.start();
        }
    }

}

LazySingleton > Thread-0 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-1 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-2 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-3 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-4 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-5 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-6 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-7 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-8 > com.test.web4.singleton.LazySingleton@5e5035fb
LazySingleton > Thread-9 > com.test.web4.singleton.LazySingleton@5e5035fb

枚举单例

  • Java虚拟机默认防止了枚举类型的序列化和反射破坏, 所以构造方法无需抛异常以及无需加 readResolve方法
  • 不会被反射破坏
  • 枚举属于饿汉式单例

public enum EnumSingleton {
    INSTENCE;

    private EnumSingleton() {}

    private Object data;

    public Object getData() {
        return data;
    }

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

    public static EnumSingleton getInstance() {
        return INSTENCE;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EnumSingleton > " + Thread.currentThread().getName() + " > " + EnumSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EnumSingleton > Thread-0 > INSTENCE
EnumSingleton > Thread-1 > INSTENCE
EnumSingleton > Thread-2 > INSTENCE
EnumSingleton > Thread-3 > INSTENCE
EnumSingleton > Thread-4 > INSTENCE
EnumSingleton > Thread-5 > INSTENCE
EnumSingleton > Thread-6 > INSTENCE
EnumSingleton > Thread-7 > INSTENCE
EnumSingleton > Thread-8 > INSTENCE
EnumSingleton > Thread-9 > INSTENCE

ConcurrentHashMap容器单例

  • 通过 ConcurrentHashMap管理多个对象, 虽然它本身是线程安全的但获取实例的方法不是, 所以需要使用同步锁

public class ContainerSingleton {
    private ContainerSingleton() {}

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

    public static Object getBean(final String className) {
        if (className != null && !"".equals(className)) {
            synchronized (className) {
                if (ioc.containsKey(className)) {
                    return ioc.get(className);
                }
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    ioc.put(className,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            }
        }
        return null;
    }

}

/**
 * 此测试类需通过反射机制实例化, 所以必须有无参构造方法
 * */
public class TestA {
    private Integer id;
    private String name;

    public TestA() {}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("ContainerSingleton > " + Thread.currentThread().getName() +
                        " > " + ContainerSingleton.getBean("com.test.web4.singleton.TestA"));
            });
            thread.start();
        }
    }

}

ContainerSingleton > Thread-0 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-1 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-2 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-3 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-4 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-5 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-6 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-7 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-8 > com.test.web4.singleton.TestA@6d559005
ContainerSingleton > Thread-9 > com.test.web4.singleton.TestA@6d559005

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值