设为首页 加入收藏

TOP

7种创建方式,带你理解Java的单例模式(一)
2023-08-26 21:11:01 】 浏览:55
Tags:方式 Java 单例模

本文分享自华为云社区《《Java极简设计模式》第01章:单例模式(Singleton)》,作者:冰 河。

单例设计模式

看几个单例对象的示例代码,其中有些代码是线程安全的,有些则不是线程安全的,需要大家细细品味,这些代码也是在高并发环境下测试验证过的。

  • 代码一:SingletonExample1

这个类是懒汉模式,并且是线程不安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程不安全的

*/

public class SingletonExample1 {

private SingletonExample1(){}

private static SingletonExample1 instance = null;

public static SingletonExample1 getInstance(){

//多个线程同时调用,可能会创建多个对象

if (instance == null){

instance = new SingletonExample1();

}

return instance;

}

}
  • 代码二:SingletonExample2

饿汉模式,单例实例在类装载的时候进行创建,是线程安全的

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 饿汉模式,单例实例在类装载的时候进行创建,是线程安全的

*/

public class SingletonExample2 {

private SingletonExample2(){}

private static SingletonExample2 instance = new SingletonExample2();

public static SingletonExample2 getInstance(){

return instance;

}

}
  • 代码三:SingletonExample3

懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程安全的,但是这个写法不推荐

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式,单例实例在第一次使用的时候进行创建,这个类是线程安全的,但是这个写法不推荐

*/

public class SingletonExample3 {

private SingletonExample3(){}

private static SingletonExample3 instance = null;

public static synchronized SingletonExample3 getInstance(){

if (instance == null){

instance = new SingletonExample3();

}

return instance;

}

}
  • 代码四:SingletonExample4

懒汉模式(双重锁同步锁单例模式),单例实例在第一次使用的时候进行创建,但是,这个类不是线程安全的!!!!!

package io.binghe.concurrency.example.singleton;

/**

* @author binghe

* @version 1.0.0

* @description 懒汉模式(双重锁同步锁单例模式)

* 单例实例在第一次使用的时候进行创建,这个类不是线程安全的

*/

public class SingletonExample4 {

private SingletonExample4(){}

private static SingletonExample4 instance = null;

//线程不安全

//当执行instance = new SingletonExample4();这行代码时,CPU会执行如下指令:

//1.memory = allocate() 分配对象的内存空间

//2.ctorInstance() 初始化对象

//3.instance = memory 设置instance指向刚分配的内存

//单纯执行以上三步没啥问题,但是在多线程情况下,可能会发生指令重排序。

// 指令重排序对单线程没有影响,单线程下CPU可以按照顺序执行以上三个步骤,但是在多线程下,如果发生了指令重排序,则会打乱上面的三个步骤。

//如果发生了JVM和CPU优化,发生重排序时,可能会按照下面的顺序执行:

//1.memory = allocate() 分配对象的内存空间

//3.instance = memory 设置instance指向刚分配的内存

//2.ctorInstance() 初始化对象

//假设目前有两个线程A和B同时执行getInstance()方法,A线程执行到instance = new SingletonExample4(); B线程刚执行到第一个 if (instance == null){处,

//如果按照1.3.2的顺序,假设线程A执行到3.instance = memory 设置instance指向刚分配的内存,此时,线程B判断instance已经有值,就会直接return instance;

//而实际上,线程A还未执行2.ctorInstance() 初始化对象,也就是说线程B拿到的instance对象还未进行初始化,这个未初始化的instance对象一旦被线程B使用,就会出现问题。

public static SingletonExample4 getInstance(){

if (instance == null){

synchronized (SingletonExample4.class){

if(instance == null){

instance = new SingletonExample4();

}

}

}

return instance;

}

}

线程不安全分析如下:

当执行instance = new SingletonExample4();这行代码时,CPU会执行如下指令:

1.memory = allocate() 分配对象的内存空间

2.ctorInstance() 初始化对象

3.instance = memory 设置instance指向刚分配的内存

单纯执行以上三步没啥问题,但是在多线程情况下,可能会发生指令重排序。

指令重排序对单线程没有影响,单线程下CPU可以按照顺序执行以上三个步骤,但是在多线程下,如果发生了指令重排序,则会打乱上面的三个步骤。

如果发生了JVM和CPU优化,发生重排序时,可能会按照下面的顺序执行:

1.memory = allocate() 分配对象的内存空间

3.instance = memory 设置instance指向刚分配的内存

2.

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【技术积累】Java 8 新特性 下一篇票据系统(补充)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目