十分钟看懂Java7种单例模式+常见的问题

什么是单例模式?

首先构造器私有 并且必须保证一个类只有一个实例

饿汉式

public class A{
	private A(){}
	private final static  A a = new A();
	private static A getA(){
		return a;
	}
}

优缺点

编程简单 但是无法延迟创建对象 浪费空间

懒汉式

见名知意 很懒 所以会延迟创建对象

单线程写法
public Class A{
	private A(){}
	private static A a;
	public static A getA(){
		if(a==null){
			a = new A();
		}
		return a;
	} 
}
多线程写法 上面的单线程写法明显是线程不安全的 因为没有做任何操作 这样在并发的时候就不安全
public Class A{
	private A(){}
	private static volatile A a;
	public static synchronized A getA(){
		if(a==null){
			a = new A();
		}
		return a;
	}
}

饿汉式的好处在于可以延迟加载 但是要反复判断锁 效率低

双重检查锁

public Class A{
	private A(){}
	private volatile static A a;
	public static getA(){
			if(a==null){
			synchronized(A.Class){
				if(a==null){
					a = new A();
				}
			}
			return a;
		}
	} 
}

常见问题:

为什么需要volatile?

因为new对象这个过程不是一个原子操作
1.先分配空间
2.执行构造方法初始化对象
3.再把对象指向这个空间
2 3 步是可能发生指令重排的 如果是单线程还好 如果是多线程 比如:A线程过来 先分配空间 然后发生指令重排 直接执行第三步 把对象指向这个空间(这个空间现在是一片虚无) 此时 线程B过来 发现这个对象!-=null(这个判空是外层的判空) 那么B就直接把这个虚无的对象返回去了。

两次非空判断目的?

第一次其实可以没有 它的作用是提高效率 避免多线程访问时每个线程都尝试获取锁
第二次是延迟加载 lazy的思想

静态内部类

双重检查锁还是有点麻烦

public Class A{
	private A(){}
	public static Class A1{
		static A a = new a A();
	}
	private static A getA(){
		return A1.a;
	}
}

=================================
上述代码都会出现一个问题 就是拦不住反射获取你的私有字段 1反射会破坏单例结构
关于反射:的确可以在私有构造里面加上判断 if(singlon!=null) xxxx但是要是都用反射的getDeclaredConstructor也不行了 然后我们可以自己再写一个boolean值的判断 但是这个值也可以通过反射获取私有字段 来更改 总之 反射就是不安全
但是newInstance方法里面明确说了 如果是枚举 就抛异常
在这里插入图片描述
枚举:

enum Type{
A,B,C,D;

static int value;
public static int getValue() {
    return value;
}

String type;
public String getType() {
    return type;
}

}

在原有的基础上,添加了类方法和实例方法。我们把Type看做一个类,那么enum中静态的域和方法,都可以视作类方法。和我们调用普通的静态方法一样,这里调用类方法也是通过 Type.getValue()即可调用,访问类属性也是通过Type.value即可访问。
下面的是实例方法,也就是每个实例才能调用的方法。那么实例是什么呢?没错,就是A,B,C,D。所以我们调用实例方法,也就通过 Type.A.getType()来调用就可以了。
最后,对于某个实例而言,还可以实现自己的实例方法。再看下下面的代码:
在这里插入图片描述
关于枚举:
反编译后 发现public final class T extends Enum 里面的变量都是public static final 的 static类型的属性会在类加载的时候被初始化 而Java类加载和初始化的过程是线程安全的

Singleton.INSTANCE.doSomeThing即可调用

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值