目标:保证一个类只有一个实例
实现:
不可被外部创建
限制外部访问方式(private)
内部保证实例唯一性
四种创建方式
1.懒汉式:因为类加载的时候静态属性就会初始化,所以在加载类的时候去调用该类中的静态方法(static)执行,该静态方法用if语句判断一个private的静态属性是否初始化,如果为初始化就给该静态属性赋一个新的构造器,最后返回一个该静态属性的值。之后每一次调用静态方法都会因为该静态属性已经初始化而导致if语句返回false,从而每次该静态方法都返回一样的值,这样就可以保证该类只有一个实例。该方式线程不安全,单线程没问题,但多线程就很可能创建出多个不同实例,所以改进方式就是DCL(double checking lock)
public class S1 {static {
System.out.println("懒汉式");
}
private static S1 instance;
private S1() {};
public static S1 getInstance() {
if(instance==null ) {
instance = new S1();
}
return instance;
}
2.饿汉式:通过静态方法在调用类的时候只执行一次特性,直接给一个静态属性赋一个新的构造器,然后通过静态方法返回该静态属性的值,因此每次调用该静态方法就是直接返回相同静态方法的值,这样就保证该类只有一个实例。该方式是线程安全的,每次加载类都会直接初始化静态属性,从而保证单例,有可能永远都不会执行到getInstance方法
static {
System.out.println("饿汉式");
}
private static S2 instance = new S2();
private S2() {};
public static S2 getInstance() {
return instance;
}
3.DCL(Double CHecking Lock):双重检查锁DCL机制,线程安全版本
这种方法跟懒汉式是差不多的,不过懒汉式在面对多线程的时候就可能会遇到一些资源同步的问题,这种双重检查锁机制就避免了这个问题,它在懒汉式的基础上加了两个if语句判断静态属性时候初始化,第二个if语句被加上了一层锁,多线程访问就必须排队用钥匙去打开锁,然后再进去通过里层的if语句,从而给静态属性赋了新的构造器,外面其他线程再开锁进来静态属性已经初始化了,就直接跳出if语句,返回相同的静态属性值,因为静态属性已经初始化了,所以多线程再去开锁效率就比较低,因此在外面再加了一个if语句判断静态属性是否初始化,从而提高效率。该方式线程安全,不去调用getInstance静态方法就不会创建实例,第一次加载不够快
static {
System.out.println("双重检查锁");
}
private static SDCL instance;
private SDCL() {};
public static SDCL getInstance() {
if(instance==null ) {
synchronized(SDCL.class) {
if(instance==null) {
instance = new SDCL();
}
}
}
return instance;
}
4.枚举:枚举的创建由JVM保证,因此不会出现并发问题,构造器自动私有,外部不能创建,只能引用,JVM反序列化组装