多线程十一 单例模式

简介: 多线程十一 单例模式

本篇博文,将整理关于单例模式(就是让一个类从始至终,只能产生一个对象,而且spring管理的类也全部是单例模式的)与多线程摩擦出的火花


1 . 懒汉模式(存在线程安全性问题)#


public class demo01 {
//要实现单例,肯定不能new对象,因此我们私有化构造函数
private demo01(){}
//定义一个属于本类的单例对象,每次返回的都是这个对象
public static demo01  instance = null;
//因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
public static demo01 getInstance(){
    if (instance==null){  //在多线程并发访问的情况下,是存在线程安全问题的
        instance = new demo01();
        return instance;
    }
    return instance;
}
}


  • 懒汉模式---在使用的时候初始化对象


2 . 饿汉模式(简单粗暴,实现线程安全)----静态域#


public class demo02 {
//要实现单例,肯定不能new对象,因此我们私有化构造函数
private demo02(){}
//定义一个属于本类的单例对象,每次返回的都是这个对象
private static demo02  instance = new  demo02();  // 静态域
//因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
public static demo02 getInstance(){
    return instance;
}
}


  • 饿汉模式---在类加载的时候初始化对象,


缺点:#


1 . 如果在构造函数中有过多的其他耗时操作的话,对象的创建会很慢

2 . 而且对象创建出来了还不一定会马上使用,造成资源的浪费


使用饿汉模式相应的注意点 :#


  1. 对象创建出来以后肯定会被使用
  2. 构造函数没有太多其他处理


3 . 饿汉模式(简单粗暴,实现线程安全)----静态块#


public class demo05 {
//要实现单例,肯定不能new对象,因此我们私有化构造函数
private demo05(){}
//注意点, 下面两段代码是有先后顺序的,假如说颠倒顺序,那么已经初始化的实例也会被重置为null
public static demo05  instance = null;
static {
    instance = new demo05();
}
//因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
public static demo05 getInstance(){
    return instance;
}
}


  • 饿汉模式---在类加载的时候初始化对象,


缺点:#


1 . 如果在构造函数中有过多的其他耗时操作的话,对象的创建会很慢

2 . 而且对象创建出来了还不一定会马上使用,造成资源的浪费


使用饿汉模式相应的注意点 :#


  1. 对象创建出来以后肯定会被使用
  2. 构造函数没有太多其他处理


4. 懒汉模式----使用synchronized实现线程安全#


public class demo03 {
//要实现单例,肯定不能new对象,因此我们私有化构造函数
private demo03(){}
//定义一个属于本类的单例对象,每次返回的都是这个对象
public static demo03  instance = null;
public static synchronized demo03 getInstance(){
    if (instance==null){
        instance = new demo03();
        return instance;
    }
    return instance;
}
}


  • 加上synchronized 在多线程并发访问的情况下,不再有线程安全问题,但是并不推荐,因为同一时间只有有一个线程进入此静态方法,因此效率低


5. 懒汉模式---- 双重同步锁单例模式+volatile 实现线程安全#


public class demo04 {
//要实现单例,肯定不能new对象,因此我们私有化构造函数
private demo04(){}
//定义一个属于本类的单例对象,每次返回的都是这个对象
public static volatile demo04 instance = null;
// 双重同步锁单例模式
public static  demo04 getInstance(){
    if (instance==null){  // 检测 1
        synchronized (demo04.class){ //锁
            if (instance==null){  //检查 2
                instance = new demo04();
            }
        }
        return instance;
    }
    return instance;
}
}


为什么要加上volatile关键字?#


这就要从CPU的指令说起, 当我们执行 


new demo04();


分下面三步走

  1. memory = allocate(); //分配内存空间
  2. ctorInstance() //初始化对象
  3. instance = memory // 将对象的引用指向刚分配的内存空间

在单线程的情况下是不会发生任何线程安全问题的,但是! 多线程就会受到 指令重排序的影响, JVM和CPU优化--指令重排序可能出现下面的顺序

  1. memory = allocate(); //分配内存空间
  2. instance = memory // 将对象的引用指向刚分配的内存空间,
  3. ctorInstance() //初始化对象

这时候双重同步锁单例模式就会出现问题,比如AB两条线程 A运行到指令3却没有真正创建对象 , 然后B去判断instance此时不为空,拿到了instance,一旦调用就会出现问题


6. 使用枚举实现单例模式 --线程安全#


public class demo06 {
private demo06(){}
public static demo06 getInstance(){
        return Singleton.INSTANCE.getDemo06Instance();
}
//私有的枚举类
private enum Singleton{
    INSTANCE;
    private demo06 demo06Instance;
    //JVM保证此构造方法绝对只会调用一次
    Singleton(){
        demo06Instance= new demo06();  //调用外部类私有的构造方法
    }
    public demo06 getDemo06Instance(){
        return demo06Instance;
    }
}
}


推荐使用这种方法

  • 相对懒汉模式,绝对性的保证的安全问题
  • 相对饿汉模式,当实例在使用的时候才开始初始化
相关文章
|
15天前
|
缓存 安全 Java
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
|
7月前
|
安全 Java
线程安全的单例模式(Singleton)
线程安全的单例模式(Singleton)
|
4月前
|
安全 Java 关系型数据库
单例模式下引发的线程安全问题
单例模式确保类在进程中仅有一个实例,适用于如数据库连接等场景。分为饿汉式与懒汉式:饿汉式在类加载时创建实例,简单但可能浪费资源;懒汉式延迟创建实例,需注意线程安全问题,常采用双重检查锁定(Double-Checked Locking)模式,并使用 `volatile` 关键字避免指令重排序导致的问题。
81 2
单例模式下引发的线程安全问题
|
3月前
|
设计模式 安全 Java
【多线程-从零开始-柒】单例模式,饿汉和懒汉模式
【多线程-从零开始-柒】单例模式,饿汉和懒汉模式
62 0
|
6月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
96 1
|
5月前
|
设计模式 SQL 安全
单例模式大全:细说七种线程安全的Java单例实现,及数种打破单例的手段!
设计模式,这是编程中的灵魂,用好不同的设计模式,能使你的代码更优雅/健壮、维护性更强、灵活性更高,而众多设计模式中最出名、最广为人知的就是Singleton Pattern单例模式。通过单例模式,我们就可以避免由于多个实例的创建和销毁带来的额外开销,本文就来一起聊聊单例模式。
112 0
|
6月前
|
微服务
多线程内存模型问题之在单例模式中,volatile关键字的作用是什么
多线程内存模型问题之在单例模式中,volatile关键字的作用是什么
|
6月前
|
设计模式 安全 Java
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
40 0
|
6月前
|
设计模式 安全 NoSQL
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
79 0
|
6月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
82 0