描述

单例模式对于开发人员来讲并不陌生通过单利模式可以控制应用程序中,只有一个对象的实例,分为饿汉式和懒汉式.饿汉式在类加载的时候就初始化,懒汉模式拥有延迟加载的思想,在使用的时候创建。实现单例模式的思想就是私有构造方法。通过getInstance()方法获取对应实例

饿汉式

1
2
3
4
5
6
7
8
public class Singleton{
private static final Singleton singleton =new Singleton();
private Singleton{
}
public static Singleton getInstance(){
return singleton;
}
}

懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton{
private static final singleton = null;
private Singleton{
}
private Singleton{
}
public static Singleton getInstance(){
if(null==singleton){
singleton =new Singleton();
}
return singleton;
}
}

上面的实现方式在多线程的环境下是线程不安全的,下面来个线程安全的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton{
// volatile 保证每次都从主内存中取,不会在工作线程内存中取,效率不高
private static volatile final singleton = null;
private Singleton{
}
public static Singleton getInstance(){
if(null==singleton){
//双重锁检查
synchronized(Singleton.class) {
if(null==singleton){
singleton =new Singleton();
}
}

}
return singleton;
}
}

下面是利用jvm加载静态内部类的方式实现单例模式.jvm初始化类

1
2
3
4
5
6
7
8
9
public class Singleton{
private static class SingletonHodle{
private static Singleton singleton =new Singleton();
public static getInstance(){
// 保证jvm加载SingletonHodle初始Singleton实例
return SingletonHodle.singleton;
}
}
}

使用枚举实现单子例模式

1
2
3
4
5
6
7
public enum Singleton {
uniqueInstance;// 定义一个枚举的元素,它就代表了Singleton的一个实例,因为枚举在编译成class文件,对应的属性就是 static final的保证了jvm初始化类的时候只能生成一个实例
public void singletonOperation() {
// 功能处理
System.err.println("功能处理");
}
}

破快单利模式的三种方式

  • 序列化
  • 反射
  • clone

    如何避免单利模式被破快

  • 序列化
    增加readResolve()方法,返回实例对象
  • 反射
    创建标志位,is_create标志,如果is_create=true 则抛异常
  • clone
    重写clone方法,返回对应的instance

jdk的实现

我们 JDK 中,java.lang.Runtime 就是经典的单例模式(饿汉式)