【并发编程】安全发布对象—单例模式升级版(1)

简介: 【并发编程】安全发布对象—单例模式升级版

发布对象

使一个对象能够被当前范围之外的代码所使用,将创建的对象保存到容器中,也可能通过某个方法返回
对象的引用,或者将引用传递到其他类的方法中
• 1
• 2

对象逸出

一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见


1、发布的对象只需要被它需要的线程被看见

2、避免对象逸出

发布错误对象:
import java.util.Arrays;
//线程不安全的
//发布对象
public class Student {
    private String[] student = {"张三","李四","王五"};
    public String[] getStudent(){
        return student;
    }
    public static void main(String[] args) {
        Student unsarePublish = new Student();
        System.out.println(Arrays.toString(unsarePublish.getStudent()));
        unsarePublish.getStudent()[1]="赵柳";
        System.out.println(Arrays.toString(unsarePublish.getStudent()));
    }
}

返回结果:


[张三, 李四, 王五]
[张三, 赵柳, 王五]


上述例子中我们可以看到,李四已经被赵柳替代,通过public 类的访问级别,发布了这些域,在外部都可以访问这些域,这样的发布对象其实是不安全的,因为无法假设其他线程会不会修改这个域,所以会导致student的值是不确定的,因此是线程不安全的。


如何来进行安全的发布对象呢:

看了网上好多博客,这里也整理了一下,我们就来使用最经典的,单例模式来设计


1 懒汉模式设计


1.1 懒汉模式

/**
 * 懒汉模式
 * 线程不安全
 */
public class LazyMode1 {
    private LazyMode1(){//私有的构造函数}
    private static LazyMode1 instance = null;//单例对象
    //在单线程下是没有问题的
    public static LazyMode1 getInstance(){
        if(instance == null){
            instance = new LazyMode1();
        }
        return  instance;
    }
}

这是一个比较正常的单例模式的,是一个线程不安全的类,那么如何让他变成一个线程安全的类呢,看下面一个例子

1.2 synchronized

/**
 * 懒汉模式
 * 线程安全
 */
public class LazyMode2 {
    private LazyMode2(){//私有的构造函数}
    private static LazyMode2 instance = null; //单例对象
    public  synchronized static LazyMode2 getInstance(){
        if(instance == null){
            instance = new LazyMode2();
        }
        return  instance;
    }

屏幕快照 2022-05-10 下午12.49.41.png

1.3 双重同步锁

/**
 * 懒汉模式
 * 但是这个类并不是线程安全的类
 */
public class LazyMode3 {
    private LazyMode3(){//私有的构造函数}
    private static LazyMode3 instance = null; //单例对象
    public static LazyMode3 getInstance(){
        if(instance == null){
            synchronized(LazyMode3.class){
                if(instance == null){
                    instance = new LazyMode3(); 
                }
            }
        }
        return  instance;
    }
}

这个案例,我们使用了双重同步锁的单例模式,但是他并不是一个线程安全的类,因为在JVM和cpu优化,发生了指令重排,在单线程下,是没有影响的,但是在多线程下,就会打乱分配的内存空间和初始化对象的顺序,就会导致我们的结果和预期的不一致,虽然这个发生的概率很小,但是会发生,所以他是线程不安全的类,那么如何能够让他成为一个线程安全的类呢,看下面的例子。


目录
相关文章
|
4月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
62 1
|
5月前
|
设计模式 缓存 Java
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
|
4月前
|
设计模式 安全 Java
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
34 0
|
4月前
|
设计模式 存储 缓存
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
39 0
|
6月前
|
设计模式 安全 Java
Java设计模式—单例模式的实现方式和使用场景
那么为什么要有单例模式呢?这是因为有的对象的创建和销毁开销比较大,比如数据库的连接对象。所以我们就可以使用单例模式来对这些对象进行复用,从而避免频繁创建对象而造成大量的资源开销。
155 1
|
安全 Java
并发编程-09安全发布对象+单例模式详解
并发编程-09安全发布对象+单例模式详解
72 0
并发编程-09安全发布对象+单例模式详解
|
安全 Java 测试技术
工作中单例模式用法及其使用场景?
工作中单例模式用法及其使用场景?
98 0
|
安全
并发编程-08安全发布对象之发布与逸出
并发编程-08安全发布对象之发布与逸出
50 0
|
开发框架 PHP
PHPfinal方法的使用场景是什么?底层原理是什么?
PHPfinal方法的使用场景是什么?底层原理是什么?
100 0
|
Java API 调度
java多线程之概念和3种创建方式(详解)
进程:一个执行的应用程序 线程:一个应用程序内的具体执行不同模块
119 0
java多线程之概念和3种创建方式(详解)