关于单例在多线程中,锁的作用是防止创建多个是实例。
由于理解不深刻,最近我走进了一个怪圈,竟然想成了防止多线程,操作同一个实例。(算了 感觉最近有点懵逼)
其实如果同时操作同一个实例需要同步,在相应的方法加锁就可以解决。
主要可以分为两大类
懒汉式:指全局的单例实例在第一次被使用时构建。
饿汉式:指全局的单例实例在类装载时构建。
几种实现方式
1、静态内部类
public class A1 {
private static class A1Holder {
private static final A1 INSTANCE = new A1();
}
public static final A1 getInstance() {
return A1Holder.INSTANCE;
}
private A1() {
}
}
由于内部类延迟加载,只有在调用getInstance时,才会初始化实例
从内部类来看是饿汉式,从外部来看是懒汉式
2、创建静态的实例,静态实例会在装载时构建。再创建静态方法获取实例,这样就能保证实例唯一。(饿汉式)
public class A2 {
private static final A2 ourInstance = new A2();
public static A2 getInstance() {
return ourInstance;
}
private A2() {
}
}
缺点:
1、可能由于初始化的太早,造成资源的浪费。
2、如果初始化本身依赖于一些其他数据,那么也就很难保证其他数据会在它初始化之前准备好。
适合: 使用单例占用资源少,不需要其他初始化数据。
3、枚举
public enum A3 {
INSTANCE;
public void fun1(){
}
}
// call A3.INSTANCE.fun1();
(Android官网不建议使用enums,占用内存多)
4、调用时创建,同步方法(懒汉式)
public class B1 {
private static B1 instance;
public static synchronized B1 getInstance(){//执行效率低
if(instance ==null){
instance = new B1();
}
return instance;
}
private B1(){}
}
4.2、双重检查
public class B2 { //Double check
private static B2 instance;
public static B2 getInstance() {
if (instance == null) { // instance 可能为中间态
synchronized (B2.class) {
if (instance == null) {
instance = new B2(); //instance 可能创建内存空间,但为形成实例
}
}
}
return instance;
}
private B2() {
}
}
4.3 双重检查 + volatile
public class B3 {
private volatile static B3 instance; //volatile 写操作时 不能读
public static B3 getInstance() {
if (instance == null) {
synchronized (B3.class) {
if (instance == null) {
instance = new B3(); //instance 可能创建内存空间,但为形成实例
}
}
}
return instance;
}
private B3() {
}
}