1、饿汉式
饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题。
优点:线程安全,无需加锁,执行效率比较高,代码简洁清晰
缺点:类加载的时候就初始化了对象,占用了空间和内存。
1.1 写法一
public class HungrySingleton {
private static final HungrySingleton INSTANCE = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return INSTANCE;
}
}
1.2 写法二,利用静态代码块的机制
public class HungryStaticSingleton {
private static final HungryStaticSingleton INSTANCE;
static {
INSTANCE = new HungryStaticSingleton();
}
private HungryStaticSingleton(){}
public static HungryStaticSingleton getInstance(){
return INSTANCE;
}
}
这两种写法都非常的简洁,也非常好好理解,饿汉式适用在单例对象较少的情况。
Spring中的IOC容器ApplicationContext是典型的饿汉式单例。
2、懒汉式
特点:类加载的时候并不会初始化,被外部调用的时候才会初始化单例对象。
2.1 简单方式
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton INSTANCE = null;
public synchronized static LazySimpleSingleton getInstance(){
if(INSTANCE == null){
INSTANCE = new LazySimpleSingleton();
}
return INSTANCE;
}
}
用synchronized 加锁,在线程数量比较多的情况下,CPU资源耗尽的情况下,会导致大量的线程出现阻塞,导致程序运行性能的大幅度下降。可以用双重检查锁的单例模式来解决这个问题。
2.2 双重检查锁方式
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton INSTANCE = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
if(INSTANCE == null){
synchronized (LazyDoubleCheckSingleton.class){
// 此处防止多个线程同时通过了第一组null判断,排队等待锁资源的情况下出现创建多个对象的问题
if(INSTANCE == null){
INSTANCE = new LazyDoubleCheckSingleton();
}
}
}
return INSTANCE;
}
}
2.3 内部类的方式(性能最优)
public class LazyInnerClassSingleton {
/**
* 虽然构造方法私有了,但是反射是可以避开的,增加null判断可以解决这个问题
*/
private LazyInnerClassSingleton(){
if(LazyHolder.INSTANCE != null){
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 内部类LazyHolder里面的逻辑需要等到外部方法调用的时候才执行
* 巧妙利用了内部类的特性
* JVM底层执行逻辑,完美地避免了线程安全的问题
*/
public static final LazyInnerClassSingleton getInstance(){
//在返回结果以前,一定会先加载内部类
return LazyHolder.INSTANCE;
}
//默认不加载
private static class LazyHolder{
private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton();
}
}
3、注册式单例
3.1 容器式单例
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();
public static Object getInstance(String className){
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
3.2 检举式单例
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance(){
return INSTANCE;
}
}