单例模式
双重检验(懒汉式DCL)
- 使用双重检查,提高效率,和线程安全性
- instance记得使用volatile
- instance = new Singleton()做了三件事:
- 给 instance 分配内存
- 调用 Singleton 的构造函数来初始化成员变量
- 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
- 第2步和第3步可能重排序,一旦按照132执行,很有可能执行到3后线程被抢,然后判断instance不为空就返回,后面使用时报空指针
- 所以使用volatile防止重排序,无论是123执行还是132执行,确保读操作不会再写操作之前(happens-before原则)。
- jdk5之前的还是回存在问题,jdk本身有bug
- instance = new Singleton()做了三件事:
为什么需要添加volatile:http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/#comments
public class Singleton {
//注意(volatile static)
private volatile static Singleton instance; //声明成 volatile
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
饿汉式
- 类加载的时候就将实例处理初始化好
class Util{
private Util(){
System.out.println("Util init");
}
private static Util util = new Util();
public static Util getUtil(){
return util;
}
}
静态内部类(推荐)
public class InnerClassMethod {
private InnerClassMethod(){}
// static: 可以直接访问(注意:static)
public static InnerClassMethod getInstance(){
// 内部类在使用的时候才会加载类
return InnerClass.instance;
}
// 使用静态内部类,使得不用实例化可以直接访问(注意:static)
private static class InnerClass{
// 类加载后初始化,内部类可以直接访问外部方法(注意:private final)
private final static InnerClassMethod instance=new InnerClassMethod();
}
}
枚举方法(推荐)
// 枚举实例在创建的时候是安全的
public enum EnumMethod {
INSTANCE
;
private int count=0;
public int getCountAndIncrease(){
count++;
return count;
}
}