线程安全的单例的几种实现方法
1. 使用synchronized
饱汉:双重检查锁定、饿汉、静态内部类、枚举 都属于利用synchronized同步原理实现
1.1 饱汉:双重检查锁定(double-checked locking)
public class SingleTon {
// 静态实例变量加上volatile
private static volatile SingleTon instance;
// 私有化构造函数
private SingleTon() {}
// 双重检查锁
public static SingleTon getInstance() {
if (instance == null) {
synchronized(SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
}
return instance;
}1.2 饿汉
1.3 静态内部类
以上的静态内部类、饿汉等模式均是通过定义静态的成员变量,以保证单例对象可以在类初始化的过程中被实例化。
这其实是利用了ClassLoader的线程安全机制。ClassLoader的loadClass方法在加载类的时候使用了synchronized关键字。
所以, 除非被重写,这个方法默认在整个装载过程中都是线程安全的。所以在类加载过程中对象的创建也是线程安全的。
1.4 枚举
枚举其实底层是依赖Enum类实现的,这个类的成员变量都是static类型的,并且在静态代码块中实例化的,和饿汉有点像, 所以他天然是线程安全的。
2. 利用CAS原理
3. 使用ThreadLocal
与前面的方式不同的是,ThreadLocal保证的是单个线程内部访问的是同一个实例,不同线程访问的不是同一个实例,即局部单例,并非全局单例。
序列化与反序列化破坏单例问题
序列化对象时,序列化前后得到对象不是同一个实例。解决办法就是在反序列化的过程中使用readResolve()方法,该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感觉,单例实现的代码如下:
参考链接:
最后更新于
这有帮助吗?