简洁明了的设计模式

简洁明了的设计模式

设计模式

一、单例模式

单例主要认识还是俩种 饿汉式懒汉式

单例模式的定义

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

简而言之:

  • 单例类只能有一个实例

  • 单例类必须自己创建自己的唯一实例

  • 单例类必须给所有其他对象提供这一实例

①饿汉式

缺点

类加载的时候就去初始化类,如果对象并没有使用,浪费内存,增加服务器负担。

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
public class HungrySingle {
// 构造方法私有化
private HungrySingle(){

}
// 单例自己创建自已的对象
private static HungrySingle hungrySingle = new HungrySingle();
// 对外提供唯一的访问方式
public static HungrySingle getInstance(){
return hungrySingle;
}
}

懒汉式

缺点

懒汉式单例在类加载并不会创建,在使用调用getInstance()方法才会创建,但是存在线程安全的问题,多线程情况下可能会出现创建多个单例的情况

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LazySingle {
private LazySingle(){

}

public static LazySingle lazySingle = null;

public static LazySingle getInstance(){
if (lazySingle == null){
lazySingle = new LazySingle();
}
return lazySingle;
}
}

怎么解决这个缺点? 加锁!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LazySingle {
private LazySingle(){

}

public static LazySingle lazySingle = null;

public static synchronized LazySingle getLazySingle(){
if (lazySingle == null){
lazySingle = new LazySingle();
}
return lazySingle;
}
}

该单例模式确实可以解决并发的问题,但是synchronized是重量级锁,效率极低不推荐使用


③双重校验锁机制

与其说是新的单例,不如说是懒汉式的一种优化方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DoubleSync
{
//初始定义为null
public static volatile DoubleSync ds = null;
//空构造
public DoubleSync(){}
//获取实例的方法
public DoubleSync getInstance(){
//第一次校验,判断是否已经实例了,为空就实例一个
if(ds==null){
//上锁,防止多线程多次实例
synchronized (DoubleSync.class){
//第二次校验
if(ds==null){
ds = new DoubleSync();
}
}
}
return ds;
}
}

两次校验的原因

第一次校验:为了防止多次创建实例导致的代码再去执行下面的锁和代码块导致的代码执行效率低下,第一次判断后可用直接返回前面创建的实例

第二次校验:主要是为了防止多线程导致的多次创建实例,举个例子,线程A、B同时进入了getInstance()方法,同样通过了第一次校验,线程B抢占了锁资源,线程A等待线程B,等B释放锁时候已经创建好了单例的对象,线程A此时占据锁,在第二次校验时,因为线程B已经实例化了,所以直接返回,避免了多线程多次创建实例

为什么加volatile关键字

volatile主要有三大特性:

  • 不保证原子性
  • 可见性
  • 防止jvm指令重新排优

原因:

singleton = new Singleton();

可以分为三步:

1.为singleton分配内存空间

2.将singleton初始化

3.将singleton指向内存空间

JVM具有指令重排的特性,执行顺序可能变成1-3-2。在单线程下没问题,但是在多线程中就可能出现获取到一个未初始化的实例