Java单例模式


Java单例模式

单例模式 | 菜鸟教程 (runoob.com)

单例模式介绍

  • 创建型模式
  • 一个类有且只有一个对象

要点:

  • 构造函数私有化
  • 类返回静态的一个对象

单例模式的 UML 图

Java几种实现方式

首先提一下懒汉模式饿汉模式

  • 懒汉:需要的时候才创建
  • 饿汉:上来就直接创建

然后就是多线程是否安全。
这里的线程安全是指,多线程可能创建多个单例对象。

1.最简单的懒汉模式

  • 懒汉
  • 线程不安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton{
// 静态实例
private static Singleton instance;
// 私有化构造函数
private Singleton(){}

// 一个返回实例的方法
public static Singleton getInstance(){
if(instace == null){
instance = new Singleton();
}
return instance;
}
}

2.懒汉模式方法加锁

  • 懒汉
  • 线程安全
1
2
3
4
5
6
7
8
9
10
11
public class Singleton{
private static Singleton instance;
private Singleton();

public static synchronized Singleton getInstace(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}

直接给get方法加了锁,可能性能较低。

3. 双重验证

DCL:double-check locking

  • 懒汉
  • 线程安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton{
// volatile禁止指令重排
private static volatile Singleton instance;
private Singleton();

public static Singleton getInstance(){
// 双重验证
if(instance == null){
// 对类加锁
synchronized(Singleton.class){
// 第二层验证,防止通过第一个判断的,阻塞中的第二个线程,得到锁后再次new
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}

4. 饿汉式

  • 饿汉
  • 线程安全
1
2
3
4
5
6
7
8
9
public class Singleton{
// 饿汉直接创建对象
private static Singleton instance = new Singleton();
private Singleton(){}

public static Singleton getInstance(){
return instance;
}
}

上来就创建,浪费内存;容易产生垃圾对象。使用了 classloader 机制来保证了线程安全。

5.静态内部类

  • 懒汉
  • 线程安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton{
private Singleton(){}

// 一个static内部类
public static class SingletonHolder{
// final关键字,并新建
private static final Singlton INSTANCE = new Singleton();
}

// get函数直接返回内部类成员
public static final getInstance(){
return SingletonHolder.INSTANCE;
}
}

SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。

6.枚举

jdk1.5之后添加了enmu;

  • 饿汉
  • 线程安全
1
2
3
4
5
6
public enmu Singleton{
INSTANCE;
public void doSomething(){
System.out.println("Do Something!");
}
}

不会被反射机制破解。

使用场景

一般直接使用饿汉式;

如要使用 懒汉式 则一般建议使用 静态内部类 的方法;

有特殊要求则使用 双重验证 方式;

如涉及 反序列化 则使用 枚举


文章作者: SongX64
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SongX64 !
  目录