返回设计模式目录
- 概念
- 代码
- 1、一般创建流程
- 2、几种实现方式
- ①饿汉式
- ②懒汉式(线程不安全)
- ③懒汉式(线程安全)
- ④双检锁
- ⑤登记式(静态内部类)
- ⑥枚举(推荐)
- 总结
采用单例模式设计的类负责创建自己的对象,并且确保只有单个对象被创建。该类需要提供一种访问其唯一对象的方式,并且可以直接访问,不需要实例化该类的对象。
代码 1、一般创建流程用单例模式设计一个类
public class SingleObject {
// 1、隐藏构造函数,禁止在其他代码中实例化该类
private SingleObject() {
}
// 2、创建该类的唯一对象
private static SingleObject instance = new SingleObject();
// 3、对外提供访问该类的唯一对象的方式
public static SingleObject getInstance() {
return instance;
}
// 4、其他代码
// …………
}
使用该类的唯一对象
public class Main {
public static void main(String[] args) {
// 1、获取唯一对象
SingleObject singleObject = SingleObject.getInstance();
// 2、调用对象的某些方法或属性
// singleObject.xxx()
}
}
2、几种实现方式
| 实现方式 | Lazy初始化 | 线程安全 |
|---|---|---|
| 饿汉式 | 否 | 是 |
| 懒汉式 | 是 | 否 |
| 懒汉式(线程安全) | 是 | 是 |
| 双检锁 | 是 | 是 |
| 登记式 | 是 | 是 |
| 枚举 | 否 | 是 |
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
饿汉式基于Java类加载机制,在加载类的时候就实例化该类,避免了多线程同步问题。但是使用这种方式容易创建垃圾对象,浪费内存。
②懒汉式(线程不安全)public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式实现方式在第一次使用该类的对象时才进行实例化,避免创建多余的对象。但是这种实现方式无法保证线程安全,在多线程环境下有可能多次进行实例化造成程序异常。
③懒汉式(线程安全)public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
对懒汉式的getInstance()方法加synchronized锁即可保证线程安全,但是这种实现方式会影响程序的执行效率,适用于getInstance()方法调用不太频繁的场景。
④双检锁public class Singleton {
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双检锁方式针对线程安全的懒汉式做了进一步的改进——只对getInstance()方法中的实例化部分代码加锁。即只在修改该类的信息的时候保证线程安全,调用该类的实例时则无需如此。这样既保证只创建一次对象,也能有较好的性能。
⑤登记式(静态内部类)public class Singleton {
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
private Singleton() {
}
public static final Singleton getInstance() {
return SingletonHolder.instance;
}
}
登记式同样利用了Java的类加载机制,不同于饿汉式,登记式利用静态内部类来确保该类只实例化一次。在外部类被加载时,静态内部类不会立刻被加载,因此外部类不会立刻被实例化。直到第一次调用getInstance()方法时,才会实例化外部类。
⑥枚举(推荐)public enum Singleton {
INSTANCE;
public void doSomething() {
}
}
使用枚举是实现单例最简单的方式。使用这种方法不仅可以避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
总结单例模式的使用场景:
某个类需要被全局使用,为了避免对象的频繁创建与销毁,可以采用单例的设计模式(比如数据库连接、I/O等)
单例模式的编码思路和习惯:
(不使用枚举)隐藏构造函数→(根据Lazy初始化和多线程同步需求修改)→private实例化→public方法提供类的对象→其他代码
(使用枚举)添加唯一的实例属性INSTANCE→其他代码
返回设计模式目录



