「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
一、单例模式是什么
单例模式是什么呢?就是有且仅有这个实例。spring的bean默认就是使用单例模式。单例要求构造方法是静态的,实例必须是static并且必须有仅有一个,提供一个公有的静态的获取实例的方法。
二、创建单例的方式
- 懒汉式
public class LazySingle {
private static LazySingle lazySingle = null;
private LazySingle() {}
public static LazySingle getInstance() {
if (lazySingle == null) {
return new LazySingle();
}
return lazySingle;
}
}
懒汉式在一开始不初始化,在需要使用的时候才初始化。如果要保证线程安全,可以对getInstance方法加锁。
- 饿汉式
public class HungrySingle {
private static HungrySingle hungrySingle = new HungrySingle();
private HungrySingle(){
}
public static HungrySingle getInstance(){
return hungrySingle;
}
}
类加载的时候就创建,不管用不用,先创建。线程安全。
- 双重加锁机制
public class DoubleLockSingle {
public static DoubleLockSingle doubleLockSingle = null;
private DoubleLockSingle(){}
public static DoubleLockSingle getInstance(){
if (doubleLockSingle==null){
synchronized (DoubleLockSingle.class){
if (doubleLockSingle==null){
doubleLockSingle = new DoubleLockSingle();
}
}
}
return doubleLockSingle;
}
}
第一种懒汉式的方式如果加锁,每次获取对象都要判断,但双重加锁机制下只有还没有创建实例的情况下需要加锁,继提升了效率,又保证了线程安全。
- 使用内部类实现
public class InnerSingle {
public static class SingleHandler{
private static InnerSingle innerSingle = new InnerSingle();
}
private InnerSingle(){}
public static InnerSingle getInstance(){
return SingleHandler.innerSingle;
}
}
双亲委派机制保证类只加载一次,实例只有在静态内部类加载的时候创建,保证了线程的安全性。加载外部类的时候,不会立即加载静态内部类,等到调用的时候才会加载,实现了延迟加载。
三、单例的使用场景
单例模式一般在什么情况下使用呢,整个程序只需要一个实例,对象经常创建然后并销毁的,多线程间通信。举个栗子,spring中注入的bean,就是单例的,开始的时候注入容器中,调用的时候都是同一个实例。或者计数器,多个线程调用的时候要保证同一个实例,计数才准确。windows的回收站也是单例模式的,只可以打开一个。
四、单例的优缺点
优点是可以全局访问,可以用于共享一些变量,由于只有一个对象可以提升性能,节省内存空间。缺点就是不适用变化频繁的对象,比如返回数据的,可扩展性差。要注意的是如果对象实例化的对象长时间未使用,系统会认为该对象是垃圾然后进行回收,导致对象状态丢失。
如果有问题,敬请大佬指正。