众所周知,单例模式的“懒汉”写法在多线程时运行可能会出现多实例,即,在多线程时,可能多个线程同时判断实例为null,然后对实例进行创建,使用双重锁对创建操作加锁可以避免多次创建。使用volatile关键字修饰对象,保证创建后主内存立即同步,避免多线程时,线程已经创建对象,但其他线程不可见,返回为null。
可以使用以下写法避免。
一:单例模式的坑怎么避免
1、使用synchronized关键字做双重检查锁
对需要判定只执行一次的操作加双重校验锁,即一次判断是否操作,一次对操作加锁。
注意:对象需要使用
/**
* 双重检查锁,解决多线程可能出现的多实例问题
*/
public class SingleTon2 {
private static volatile SingleTon2 singleton;
private SingleTon2() {
}
public static SingleTon2 getInstance() {
if (singleton == null) {
synchronized (SingleTon2.class) {
if (singleton == null) {
singleton = new SingleTon2();
}
}
}
return singleton;
}
//类中其他方法,尽量是static
public static void doSomething() {
System.out.println("this is a singleInstance");
}
}
2、使用枚举类获取单例
单例类如下:
/**
* 用于演示枚举类单例
*/
public class SingleTon3 {
//类中其他方法,尽量是static
public static void doSomething() {
System.out.println("this is a singleInstance");
}
}
单例类对应枚举如下:
/**
* 单元素枚举类单例
* 原理:枚举中枚举是 static final 的
* 访问枚举实例时会执行构造方法,在调用构造方法时,我们的单例被实例化。
* enum中的实例被保证只会被实例化一次,所以我们的INSTANCE也被保证实例化一次。
* <p>
* 使用,使用 SingleTonEnum.INSTANCE.getInstance()获取单例
*
*/
public enum SingleTonEnum {
INSTANCE;
private SingleTon3 singleTon;
SingleTonEnum() {
singleTon = new SingleTon3();
}
public SingleTon3 getInstance() {
return singleTon;
}
}
说的好,我选择饿汉模式,哈哈哈哈哈
关于单例,还有一个是可能的序列化如何破坏单例模式,个人觉得没必要在意