设计模式种类比较多,总共有23种,今天主要来讲下使用最频繁的---单例模式。
优点:
1.保证整个进程运行过程中此类有且只有一个对象。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它
2.减少内存开支,防止了重复的创建和回收;
3.可以设置全局的访问点,优化和共享资源访问
适用场景:
- 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
- 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
使用单例模式可以提高程序的可靠性和安全性,但也需要注意避免过度依赖单例模式,以免导致程序的扩展性和灵活性受到影响。
实现方式:
1.饿汉模式:在类加载时创建实例
public class SingletonDemo { private static final SingletonDemo instance=new SingletonDemo(); private SingletonDemo(){ } public static SingletonDemo getInstance(){ return instance; } }
避免了线程同步问题;缺点是在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
2.懒汉模式:在第一次调用时创建实例
ublic class SingletonDemo { private static SingletonDemo instance; private SingletonDemo(){ } public synchronized static SingletonDemo getInstance(){ if(instance==null){ instance=new SingletonDemo(); } return instance; }}
实现了懒加载的效果,线程安全。
缺点:每次调用getInstance都进行同步,造成不必要的同步开销。
3.双重检查枷锁模式:(Double Checked Locking):使用两个锁相互保护,一个用于保护静态变量,一个用于保护实例变量。
public class SingletonDemo { private volatile static SingletonDemo instance; private SingletonDemo(){ } public static SingletonDemo getInstance(){ if(instance==null){ synchronized (SingletonDemo.class){ if(instance==null){ instance=new SingletonDemo(); } } } return instance; }}
优点:
- 安全性高:双重检查锁定模式采用双重检查锁定机制,可以保证线程安全。
- 性能好:在多线程环境下,双重检查锁定模式可以保证线程安全的前提下,尽可能地提高并发访问共享资源的效率。
缺点:
- 效率低:双重检查锁定模式需要进行两次检查锁定操作,相对于同步原语来说比较耗时。
- 竞争条件多:由于双重检查锁定模式需要进行两次检查锁定操作,当多个线程同时访问共享资源时,可能会出现竞争条件,影响访问效率。
volatile:可以保证可见性,禁止指令重排,但不能保证原子性。
4.静态内部类式(Static Inner Class):在类加载时创建实例。
public class SingletonDemo { private SingletonDemo(){ } public static SingletonDemo getInstance(){ return StaticInner.instance; } private static class StaticInner{ private static final SingletonDemo instance=new SingletonDemo(); }}
使用时实例化,线程安全,没有多余的同步,比较推荐
5.枚举式(Enum):使用枚举类型实现单例模式。
public enum SingletonDemo { INSTANCE; private SingletonDemo() { // 私有构造函数,防止外部类直接实例化 } public static SingletonDemo getInstance() { return INSTANCE; }}
使用枚举实现单例模式,实现简单、调用效率高,枚举本身就是单例,由JVM从根本上提供保障,避免通过反射和反序列化的漏洞。
总结:每种单例都有优劣,可根据实际业务使用场景使用。