23种设计模式(1)-单例模式

定义

属于创建型模式,提供了一种创建对象的最佳方式。涉及到一个单一的类,该类负责创建自己的对象,同时保证只有单个对象被创建。

注意:

  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例

介绍

主要解决:一个全局使用的类的对象被频繁地创建于销毁

何时使用:想要控制某个类的实例的数目,节省系统资源的时候

关键:构造函数私有

自己加的理解:在程序中,对象销毁之后,重新创建对象不叫单例模式(这种可以通过同步机制实现);只有程序运行期间,一个类只创建一次对象,且只有这一个对象,才叫单例模式

几种实现方式

饿汉式

优点:避免了多线程的同步问题

缺点:容易产生垃圾对象;可以通过反射破解,构造出新的对象。

1
2
3
4
5
6
7
8
9
10
11
public class HungryMan {

private static HungryMan hungryMan = new HungryMan(); //预先创建好实例

private HungryMan() { //构造函数私有化
}

public static HungryMan getInstance() {
return hungryMan;
}
}

DCL懒汉式(DCL,即double-checked locking)

优点:①使用DCL懒汉式,可以保证程序在多线程情况下,也是可以正确运行的

​ ②由于获取锁需要消耗资源,所以在synchronized加锁外面再套一层if判断

缺点:还是防不了反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LazyMan {

private volatile static LazyMan lazyMan; //保证是一个原子性操作,避免指令重排

private LazyMan() {
}

public LazyMan getInstance() {
if (lazyMan == null){ //先进行一层判断,避免每次都要获取锁的过程,不能因为每次都在锁外面等候,大大提高效率
synchronized (LazyMan.class) { //同步获取HungryMan的锁,解决多线程问题(第一重锁)
if (lazyMan == null) { //保证只有一个实例对象,但不是原子性操作(第二重锁)
lazyMan = new LazyMan();
/**
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*/
}
}
}
return lazyMan;
}
}

枚举(最佳)

优点:避免多线程同步问题支持自动序列化机制防止反序列化、也不能通过反射构造对象

机制:

1
2
3
4
5
6
7
public enum EnumMan {
INSTANCE;

public EnumMan getInstance(){
return INSTANCE;
}
}

在枚举中,可以直接获得实例化对象,将实例化对象作为枚举中的要素,可以将要单例的类直接设置为枚举类型

Contents
  1. 1. 定义
  2. 2. 介绍
  3. 3. 几种实现方式
    1. 3.1. 饿汉式
    2. 3.2. DCL懒汉式(DCL,即double-checked locking)
  4. 4. 枚举(最佳)
|