Java单例七种方式

第一种:懒汉

调用判断为空时才去创建实例,缺点:线程不安全容易造成死锁,个人不推荐这种方式实现

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton {  
private static Singleton instance;

private Singleton (){}

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

第二种:懒汉 加同步锁

为解决第一种方式线程不安全的问题加入了同步锁; 但是每次获取实例都需要加锁, 不推荐
优点:线程安全不用担心多线程调用, 缺点:大多数情况不需要同步,效率低

1
2
3
4
5
6
7
8
9
10
public class Singleton2 {
private static Singleton2 instance;
private Singleton2(){}
public static synchronized Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}

第三种: 饿汉

这种方式基于classloder加载机制避免了多线程的同步问题, 但是内存中始终存在一个我们有可能不用的实例对象,很浪费

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

}

private static Singleton instance = new Singleton();

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

第四种: 饿汉 变种

用static代码块来加载对象,但JVM加载类时会执行这些静态的代码块,同样没有达到lazy loading的效果,其优缺点和第三种一样

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {  
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}

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

第五种:静态内部类

同样基于classloder加载机制,解决了懒汉式中多线程的问题.并且当只有我们调用了getInstance()获取实例时,才会创建唯一的实例到内存中也实现了延迟加载。

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

private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

private Singleton (){}

public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

第六种: 枚举

优点:线程安全, 防止反序列化重新创建新的对象
Java1.5才出现enum特性,使用时注意

1
2
3
4
5
public enum Singleton {  
INSTANCE;
public void whateverMethod() {
}
}

第七种: 双重校验模式

最常用的一种

加入同步锁避免多线程调用的问题;提前判断实例对象避免每次进入同步锁(这样只是在初始化对象的时候执行同步锁)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {  
private volatile static Singleton singleton;

private Singleton (){}

public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

注意

以上除第六种枚举外其他如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会产生多个单例类的实例
这种情况解决:

1
2
3
4
5
6
7
8
9
10
public class Singleton implements java.io.Serializable {     
public static Singleton INSTANCE = new Singleton();

protected Singleton() {

}
private Object readResolve() {
return INSTANCE;
}
}