目录
单例模式有以下特点:
-
单例类只能有一个实例。
-
单例类必须自己创建自己的唯一实例。
-
单例类必须给所有其他对象提供这一实例。
懒汉式单例(延迟加载单例类)
-
优点: 资源利用率高,不执行getInstance()不被实例化,可以执行该类其他静态方法
-
缺点: 第一次加载时反应不够快
类加载的时候不是实例化,使用getInstance的时候再创建实例
方式1:非延迟加载单例类,
使用静态变量(静态变量只会加载一次)
同时调用getInstance的时候会出现线程不安全
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}//避免了外部实例化
private static Singleton single=null;
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
方式2:同步延迟加载
getInstance方法上加同步语句synchronized
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}//避免了外部实例化
private static Singleton single=null;
//同步方法,开销比较大
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
方式3:双重校验锁延迟加载
public class Singleton{
private volatile static Singleton single = null;
private Singleton() {};
public static Singleton getInstance() {
if (single == null){
synchronized(Singleton.class){
if(single == null){//避免两个线程都第一次实例化这个类
single = new Singleton();
}
}
}
return single;
}
}
多线程使用导致不必要的同步开销大
对于为什么要加volatile关键字的理解?
禁止指令重排。
因为single=new Single();是非原子操作,很用可能在另一个线程判断的时候会看到一个还未初始化的实例,导致程序崩溃。
详见:https://blog.youkuaiyun.com/u010002184/article/details/111876327
方式4:静态内部类(线程安全)
因为内部类加载时会加上同步锁
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
饿汉式单例(非延迟加载)
-
优点 : 1.线程安全 2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
-
缺点 : 资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
//饿汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}//避免了外部实例化
private static Singleton single=new Singleton();
//静态工厂方法
public static Singleton getInstance() {
return single;
}
}