饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
饿汉式单例类:在类初始化时,已经自行实例化。
双重检验锁
public class Singleton {
private volatile static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
volatile关键字:防止指令重排。
这是因为 instance = new Singleton()这一步操作不是原子性操作(所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch ),在执行的过程中,需要3步处理1.instance 分配内存 2.instance 调用起构造函数 3.instance 指向内存分配区域 1--2--3,但有点时候jvm会将其重排序,可能1--3--2,在线程B调用的时候,instance 不是null,但它可能没有进行初始化,导致空指针。
静态内部类
public class Singleton {
private Singleton(){
}
private static class SingleInner{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingleInner.instance;
}
}
加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。 由于在调用 Singleton.getInstance() 的时候,才会对单例进行初始化,而且通过反射,是不能从外部类获取内部类的属性的;由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性。
枚举
public enum Singleton {
instance;
public void otherMethods(){
System.out.println("Something");
}
}
Effective Java作者Josh Bloch 提倡的方式,解决了以下三个问题:
(1) 自由序列化。
(2) 保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量)。
(3) 线程安全。