饿汉式
在声明时随着类的加载就加载到内存中
public class Ehan {
private static final Ehan INSTANCE = new Ehan();
private Ehan() {}
public Ehan getINSTANCE() {
return INSTANCE;
}
}
注意
1.类的构造器是私有的
2.唯一实例化类用static和final修饰,static保证随着类的加载而初始化,final保证对象不会被修改
3.声明一个get方法,获取该单例的实例
懒汉式
饿汉式有一个很明显的问题,那就是无论是否需要,都会被加载到内存中,为了解决这个问题就产生了懒汉式
public class LHan {
private static volatile LHan lHan = null;
public static LHan getInstance() {
if (lHan == null) {
synchronized (LHan.class) {
if (lHan == null) {
lHan = new LHan();
}
}
}
return lHan;
}
}
注意
1.懒汉式不会再类的加载过程中被实例化,而是实际需要的过程中去创建。
2.创建时需要应对线程安全,且注意内层的判空,没有内层判空等于没有加锁。
3.单例对象最好声明为volatile的,因为如果开启了JIT,JVM优化之后,本地代码重排,可能导致未被初始化就返回INSTANCE的情况
枚举处理单例
在effective java中引入改了方法实现单例
public enum Mj {
INSTANCE;
private String name = "JayHoo";
public String getName() {
return name;
}
public static void main(String[] args) {
System.out.println(Mj.INSTANCE.getName());
}
}
书中对该方法的说法是
这种方法在功能上与公有方法相似,但更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型经常成为实现Singleton的最佳方法。注意,如果Singleton必须扩展一个超类,而不是扩展Enum的时候,则不适宜使用这个方法。
其实,这个方法本身也是使用了枚举对象会随着类加载而加载,让JVM实现单例以及保证线程安全。