饿汉模式
特点:线程安全,在加载类的时候实例化,因为只加载一次所以只会创建一个实例,但是实例即使不用也会一直保存在内存里,会占用内存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return instance;
}
}
懒汉模式(两种模式)
线程不安全的
特点:线程不安全,在需的时候实例化。
分析:因为new是分两步走的,一步是创建内存对象,一步是将引用变量指向内存变量,当并发的时候可能会出现线程A创建了内存a但还没指向内存a,线程B看这个instance还是null就又去创建了一块内存b,然后将instance指向内存b,这样两个线程获取到的实例就不是同一个。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程安全的
特点:线程安全,但是每次使用都会加锁影响性能。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
枚举
特点:线程安全、简单、第一次使用加载。
分析:枚举除了不能被继承外几乎可以看成一个类,枚举在被编译后它的实例实际上都是static的,每个实例也只会被初始化一次,这个是由虚拟机保证的。在使用枚举的时候才会加载枚举,这整个过程和用静态内部类实现单例很相似。
public enum Singleton {
INSTANCE;
public void doSomeThing() {}
}
双重检查
特点:线程安全,第一次使用加载
分析:没有加volatile的双重检查在 J2SE 1.4 或早期版本在多线程或者 JVM 调优时会无序写入,是不可用的。加入volatile后才可以保证它的有序性。
public class Singleton {
private volatile static Singleton instance;
private Sinleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类
特点:第一次获取的时候初始化实例、代码简洁、线程安全。是比较推荐的模式。
分析:是对线程安全的懒汉模式的优化,第一次getInstance()的时候加载SingletonHolder类,然后instance才会被实例化,还是因为类只会加载一次,static代码也只会在类被加载的时候执行一次,所以只有一个instance实例。
public class Singleton {
private Singleton(){}
public static class SingletonHolder {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
容器获取
特点:管理多种类型的单例,通过统一接口获取操作。但是如果key的hash值一样后面的会覆盖前面的。
public class Singleton {
private static Map<String, Object> objMap = new HashMap<String, Object>;
private Singleton() {}
public static void registerService(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);
}
}
pulbic static Object getService(String key) {
return objMap.get(key);
}
}