龙空技术网

面试常问的单例模式,及懒汉式单例模式的线程安全解决方案

深海飝鲨 296

前言:

目前你们对“懒汉模式线程安全吗”都比较关切,你们都想要知道一些“懒汉模式线程安全吗”的相关资讯。那么小编在网络上汇集了一些有关“懒汉模式线程安全吗””的相关资讯,希望看官们能喜欢,兄弟们快快来了解一下吧!

一、饿汉式

/**

* 单例模式:饿汉式

* 类加载时创建类的实例,没吃饱早些吃饱

*/

public class Singleton

{

//1.将构造方法私有不允许外部new对象

private Singleton()

{

}

//2.创建类的唯一实例

private static Singleton singleton = new Singleton();

//3.提供一个获取实例的方法

public static Singleton getInstance()

{

return singleton;

}

}

二、懒汉式

/**

* 懒汉式

* 类加载时并不会常见实例,当用户获取时,如果实例为空创建实例

*/

public class Singleton2

{

//1.将构造函数私有,不允许外部创建

private Singleton2()

{

}

//2.声明类的唯一实例

private static Singleton2 instance;

//3.提供一个实例获取的方法

public Singleton2 getInstance()

{

if (instance == null)

{

instance = new Singleton2();

}

return instance;

}

}

三、懒汉式的线程安全解决方法

public class Singleton3

{

//1.将构造函数私有,不允许外部创建

private Singleton3()

{

}

//2.声明类的唯一实例

private static volatile Singleton3 instance;////第二层锁,volatile关键字禁止指令重排

//3.提供一个实例获取的方法

public Singleton3 getInstance()

{

if (instance == null)

{

synchronized (Singleton3.class)//第一层锁,保证只有一个线程进入

{

//双重检查,防止多个线程同时进入第一层检查(因单例模式只允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)

//当某一线程获得锁创建一个Singleton对象时,即已有引用指向对象,singleton不为空,从而保证只会创建一个对象

//假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入对象也会创建对象,会产生多个对象

if (instance == null)//第二层检查

{

//volatile关键字作用为禁止指令重排,保证返回Singleton对象一定在创建对象后

//singleton=new Singleton语句为非原子性,实际上会执行以下内容:

//(1)在堆上开辟空间;(2)初始化实例;(3)引用指向对象

//假设以上三个内容为三条单独指令,因指令重排可能会导致执行顺序为1->3->2

// (正常为1->2->3),当单例模式中存在普通变量需要在构造方法中进行初始化操作时,

// 单线程情况下,顺序重排没有影响;但在多线程情况下,

// 假如线程1执行singleton=new Singleton()语句时先1再3,

// 由于系统调度线程2的原因没来得及执行步骤2,

// 但此时已有引用指向对象也就是singleton!=null,

// 故线程2在第一次检查时不满足条件直接返回singleton,

// 此时singleton为null(即str值为null)

//volatile关键字可保证singleton=new Singleton()语句执行顺序为123,

// 因其为非原子性依旧可能存在系统调度问题(即执行步骤时被打断),

// 但能确保的是只要singleton!=0,就表明一定执行了属性初始化操作;

// 而若在步骤3之前被打断,此时singleton依旧为null,

// 其他线程可进入第一层检查向下执行创建对象

instance = new Singleton3();

}

}

}

return instance;

}

}

标签: #懒汉模式线程安全吗 #懒汉模式为什么不安全 #懒汉单例模式不存在线程安全问题 #单例模式懒汉和饿汉线程安全