Java常见单例模式
单例模式就是为确保一个类只有一个实例,减少了内存的开销,避免了资源多重占用,并为整个系统提供一个全局访问点的一种方法
饿汉式
饿汉单例模式在类加载的时候就立即初始化,并且创建单例对象。它绝对线程安全,在线程还没出现以前就实例化了,不可能存在访问安全问题。
优点:没有加任何锁、执行效率比较高,用户体验比懒汉式单例模式好。
缺点:类加载时候就初始化,不管是否使用都占用空间,浪费内存。
// 常规写法
public class Singleton{
private static final Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
// 饿汉式静态块单例模式
public class Singleton{
private static final Singleton singleton;
static{
singleton = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式
懒汉式单例模式的特点是:被外部类调用的时候内部类才会加载。
// 常规写法 线程不安全
public class Singleton{
private static Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton = null){
singleton = new Singleton();
}
return singleton
}
}
// 双重检查锁写法 线程安全
public class Singleton{
private volatile static Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
内部类单例模式实现
public class Singleton{
// 如果未使用,则内部类不加载
private Singleton(){
if(LazyHolder.LAZY != null){
throw new RuntimeException("不允许创建多个实例")
}
}
// static 是为了单例空间共享,保证这个方法不会被重写、重载
public static final Singleton getInstance(){
// 返回结果在一定会先加载内部类
return LazyHolder.LAZY;
}
// 默认不加载
private static class LazyHolder{
private static final Singleton LAZY = new Singleton();
}
}
注册式单例模式
注册式单例模式又称为登记式单例模式,将每一个实例都登记到某一个地方,使用唯一的标识获取实例。注册式单例模式有两种:一种为枚举式单例模式、另一种为容器式单例模式。
枚举式单例
枚举类型通过类名和类对象找到一个唯一的枚举对象,因此枚举对象不可能被类加载器加载多次。
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;
}
}
反编译代码:枚举式单例模式在静态代码块中就给INSTANCE进行了赋值
static {
INSTANCE = new EnumSingleton("INSTANCE", 0);
$VALUS = (new EnumSingleton[] {
INSTANCE;
});
}
容器式单例
容器便于管理,但是非线程安全。
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();
public static Object getBean(String className){
synchronized (ioc) {
if(!ioc.containsKey(className)){
Object obj = null;
try {
obj = Class.forName(className).newInstance();
} catch (Exception e){
e.printStackTrace();
}
}else{
return ioc.get(className);
}
}
}
}