当前位置:首页 >焦点 >我们一起聊聊Java极简设计模式:单例模式(Singleton) 起模式模式多一句没有

我们一起聊聊Java极简设计模式:单例模式(Singleton) 起模式模式多一句没有

2024-06-28 10:22:28 [百科] 来源:避面尹邢网

我们一起聊聊Java极简设计模式:单例模式(Singleton)

作者:冰河 开发 前端 单例设计模式(Singleton),起模式模式多一句没有,聊聊少一句不行,极简用最简短的设计篇幅讲述设计模式最核心的知识,好了,单例开始今天的起模式模式内容。看几个单例对象的聊聊示例代码,其中有些代码是极简线程安全的,有些则不是设计线程安全的,需要大家细细品味,单例这些代码也是起模式模式冰河本人在高并发环境下测试验证过的。
  • 本章难度:★★☆☆☆
  • 本章重点:介绍创建Java单例对象的聊聊七种方式,重点掌握哪些创建方式是极简线程安全的,哪些方式是设计线程不安全的,并能够在实际项目中灵活运用设计模式,单例编写可维护的代码。

大家好,我是冰河~~

今天给大家介绍《Java极简设计模式》的第01章,单例设计模式(Singleton),多一句没有,少一句不行,用最简短的篇幅讲述设计模式最核心的知识,好了,开始今天的内容。

我们一起聊聊Java极简设计模式:单例模式(Singleton) 起模式模式多一句没有

单例设计模式

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

我们一起聊聊Java极简设计模式:单例模式(Singleton) 起模式模式多一句没有

  • 代码一:SingletonExample1

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

我们一起聊聊Java极简设计模式:单例模式(Singleton) 起模式模式多一句没有

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.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使用,就会出现问题。

  • 代码五:SingletonExample5

懒汉模式(双重锁同步锁单例模式)单例实例在第一次使用的时候进行创建,这个类是线程安全的,使用的是 volatile + 双重检测机制来禁止指令重排达到线程安全

package io.binghe.concurrency.example.singleton;/** * @author binghe * @version 1.0.0 * @description 懒汉模式(双重锁同步锁单例模式) *              单例实例在第一次使用的时候进行创建,这个类是线程安全的 */public class SingletonExample5 {     private SingletonExample5(){ }    //单例对象  volatile + 双重检测机制来禁止指令重排    private volatile static SingletonExample5 instance = null;    public static SingletonExample5 getInstance(){         if (instance == null){             synchronized (SingletonExample5.class){                 if(instance == null){                     instance = new SingletonExample5();                }            }        }        return instance;    }}
  • 代码六:SingletonExample6

饿汉模式,单例实例在类装载的时候(使用静态代码块)进行创建,是线程安全的

package io.binghe.concurrency.example.singleton;/** * @author binghe * @version 1.0.0 * @description 饿汉模式,单例实例在类装载的时候进行创建,是线程安全的 */public class SingletonExample6 {     private SingletonExample6(){ }    private static SingletonExample6 instance = null;    static {         instance = new SingletonExample6();    }    public static SingletonExample6 getInstance(){         return instance;    }}
  • 代码七:SingletonExample7

枚举方式进行实例化,是线程安全的,此种方式也是线程最安全的

package io.binghe.concurrency.example.singleton;/** * @author binghe * @version 1.0.0 * @description 枚举方式进行实例化,是线程安全的,此种方式也是线程最安全的 */public class SingletonExample7 {     private SingletonExample7(){ }    public static SingletonExample7 getInstance(){         return Singleton.INSTANCE.getInstance();    }    private enum Singleton{         INSTANCE;        private SingletonExample7 singleton;        //JVM保证这个方法绝对只调用一次        Singleton(){             singleton = new SingletonExample7();        }        public SingletonExample7 getInstance(){             return singleton;        }    }}


责任编辑:武晓燕 来源: 冰河技术 单例设计模式

(责任编辑:探索)

    推荐文章
    热点阅读