软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。汇总目录链接:【玩转23种Java设计模式】学习目录汇总整理
@TOC
一、简介
某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
单例模式是大厂热门的面试考点!
二、实例
1、懒汉单例类(LazySingleton)
懒汉式,线程不安全。
public class LazySingleton {
private static LazySingleton instance;
// 私有的构造方法
private LazySingleton() {
}
public static LazySingleton getInstance() {
// 被动创建,在真正需要使用时才去创建
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- 优点:第一次调用才初始化,避免内存浪费。
- 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
2、饿汉单例类(HungrySingleton)
饿汉式,线程安全
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
// 私有的构造方法
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return instance;
}
}
- 优点:没有加锁,执行效率会提高。
- 缺点:类加载时就初始化,浪费内存。
3、双检锁/双重校验锁
(大厂面试热点)线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
双重检查模式,进行了两次的判断:
- 第一次是为了避免不必要的实例;
- 第二次是为了进行同步,避免多线程问题。
由于singleton = new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。
三、总结
1、优点
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
- 避免对资源的多重占用(比如写文件操作)。
- 可以在系统设置全局访问点,优化和共享全局资源访问。
2、缺点
- 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
3、应用场景
- 要求生产唯一序列号。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
- 在整个项目中需要一个共享访问点或者共享数据,如WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。