设计模式--单例模式

86 阅读3分钟

设计模式种类比较多,总共有23种,今天主要来讲下使用最频繁的---单例模式。 

优点:

1.保证整个进程运行过程中此类有且只有一个对象。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它

2.减少内存开支,防止了重复的创建和回收;

3.可以设置全局的访问点,优化和共享资源访问

适用场景:

  1. 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
  2. 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

使用单例模式可以提高程序的可靠性和安全性,但也需要注意避免过度依赖单例模式,以免导致程序的扩展性和灵活性受到影响。

实现方式:

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;    }}

优点:

  1. 安全性高:双重检查锁定模式采用双重检查锁定机制,可以保证线程安全。
  2. 性能好:在多线程环境下,双重检查锁定模式可以保证线程安全的前提下,尽可能地提高并发访问共享资源的效率。

缺点:

  1. 效率低:双重检查锁定模式需要进行两次检查锁定操作,相对于同步原语来说比较耗时。
  2. 竞争条件多:由于双重检查锁定模式需要进行两次检查锁定操作,当多个线程同时访问共享资源时,可能会出现竞争条件,影响访问效率。

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从根本上提供保障,避免通过反射和反序列化的漏洞。

总结:每种单例都有优劣,可根据实际业务使用场景使用。