【并发编程】安全发布对象

原文:慕课网高并发实战(五)- 安全发布对象

发布对象

发布对象:使一个对象能够被当前范围之外的代码所使用
对象溢出:一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见

不正确的发布可变对象导致的两种错误:

1、发布线程意外的所有线程都可以看到被发布对象的过期的值
2、线程看到的被发布对象的引用是最新的,然而被发布对象的状态却是过期的

下面使用代码对不安全的发布和对象溢出进行说明:
不安全的发布示例

import com.gwf.concurrency.annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;

/**
 * 不安全的发布
 * @author gaowenfeng
 * @date 2018-03-19
 */
@Slf4j
@NotThreadSafe
public class UnsafePublish {
    private String[] states = {"a","b","c"};

    /**
     * 通过public发布级别发布了类的域,在类的外部,任何线程都可以访问这个域
     * 这样是不安全的,因为我们无法检查其他线程是否会修改这个域导致了错误
      * @return
     */
    public String[] getStates() {
        return states;
    }

    public static void main(String[] args) {
        UnsafePublish unsafePublish = new UnsafePublish();
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

        unsafePublish.getStates()[0] = "d";
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

    }
}

对象溢出示例

/**
 * 对象溢出
 * 在对象构造完成之前,不可以将其发布
 * @author gaowenfeng
 * @date
 */
@Slf4j
@NotThreadSafe
@NotRecommend
public class Escape {

    private int thisCannBeEscape = 0;

    public Escape(){
        new InnerClass();
    }

    /**
     * 包含了对封装实例的隐藏和引用,这样在对象没有被正确构造完成之前就会被发布,由此导致不安全的因素在里面
     * 导致this引用在构造期间溢出的错误,他是在构造函数构造过程中启动了一个线程,造成this引用的溢出
     * 新线程只是在对象构造完毕之前就已经看到他了,所以如果要在构造函数中创建线程,那么不要启动它,
     * 而是应该才用一个专有的start,或是其他的方式统一启动线程
     * 使用工厂方法和私有构造函数来完成对象创建和监听器的注册来避免不正确的发布
     */
    private class  InnerClass{
        public InnerClass(){
            log.info("{}",Escape.this.thisCannBeEscape);
        }
    }

    public static void main(String[] args) {
        new Escape();
    }
}

安全发布对象

安全发布对象有以下四种方法:
1、在静态初始化函数中初始化一个对象引用
2、将对象的引用保存到volatile类型域或者AtomicReference对象中
3、将对象的引用保存到某个正确构造的final类型域中
4、将对象的引用保存到一个由锁保护的域中

1和2实例参考双重检测机制的线程安全的单例模式、4的实例可以参考线程安全的懒汉式单例模式。线程安全的单例模式的几种实现方式参考: 单例模式

原文地址:https://www.cnblogs.com/z00377750/p/9226840.html

时间: 2024-11-06 03:44:16

【并发编程】安全发布对象的相关文章

JAVA并发编程学习笔记------对象的可见性及发布逸出

一.非原子的64位操作: 当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性.最低安全性适用于绝大多数变量,但存在一个例外:非volatile类型的64位数值变量(double,long),Java内存模型要求,变量的读取和写入操作都必须是原子操作,但对于非volatile型的long,double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作,当读取一个非volatile类型的long

Java并发编程实践之对象的组合

---恢复内容开始--- 1 对象组合的目的 将一些现有的线程安全类组合成更大的组件,也是线程安全的: 1.1 构造线程安全的类需要考虑: 构成对象状态的所有变量: 对象变量的不变性条件(对象的变量都有取值范围,要保证变量的取值都在这个范围内, 否则,对象的状态就是无效的): 建立对象状态的并发管理策略: 1.2 类的不变性条件和类的后验条件 不变性条件:变量都有一个取值范围,比如 long count,count的取值范围是Long.MIN_VALUE,Long.MAX_VALUE, 再加上自

[Java并发编程实战] 共享对象之可见性

「 盛年不重来,一日难再晨,及时当勉励,岁月不待人.」 陶渊明 我们已经知道同步代码块和同步方法可以保证以原子的方式执行,其实,同步还有另外一个重要概念:内存可见性.换句话说,我们不仅希望防止某个线程正在使用对象状态而另一个线程同时在修改状态,而且希望确保当一个线程修改了对象的状态后,其他线程能够看到修改后的状态. 可见性 一个线程对共享变量值的修改,能够及时的被其他线程看到.可见性微妙的,这是因为可能发生错误的事情总是与直觉大相径庭.来看下面这个例子和他的执行结果: 1public class

Java并发编程 - 如何进行安全发布

首先让我简单解释一下所谓"发布". 发布(publish),使对象可以在当前作用域之外的代码中可见,如果该对象被发布,则该对象的非私有域中引用的所有实例同样也会被发布. 不仅仅是作为一个field,当一个对象作为一个方法的参数或者在公有方法中作为返回引用,这都属于发布. 而相对地,对于错误的发布,我们将其称为逸出(escape). 那么,什么是"错误的发布"? 比如发布导致封装性的破坏(可能直接导致无法安全地进行继承).线程安全性问题(尤其是不变性条件的破坏). 仅

Java 并发编程(二)对象的不变性和安全的发布对象

一.不变性 满足同步需求的另一种方法是使用不可变对象(Immutable Object).到目前为止,我们介绍了许多与原子性和可见性相关的问题,例如得到失效数据,丢失更新操作或光查到某个对象处于不一致的状态等等,都与多线程视图同时访问同一个可变的状态相关.如果对象的状态不会改变,那么这些问题与复杂性也就自然消失了. 如果某个对象在被创建后其状态就不能被修改,那么这个对象就被成为不可变对象.线程安全型是不可变对象的固有属性之一,他们的不变性条件是由构造函数创建的,只要他们的状态不改变,那么这些不变

Java 并发编程(二)对象的发布逸出和线程封闭

对象的发布与逸出 "发布(Publish)"一个对象是指使对象能够在当前作用域之外的代码中使用.可以通过 公有静态变量,非私有方法,构造方法内隐含引用 三种方式. 如果对象构造完成之前就发布该对象,就会破坏线程安全性.当某个不应该发布的对象被发布时,这种情况就被称为逸出(Escape). 下面我们首先来看看一个对象是如何逸出的. 发布对象最简单的方法便是将对象的引用保存到一个共有的静态变量中,以便任何类和线程都能看见对象,如下面代码. public static Set<Stri

《java并发编程实战》读书笔记2--对象的共享,可见性,安全发布,线程封闭,不变性

这章的主要内容是:如何共享和发布对象,从而使它们能够安全地由多个线程同时访问. 内存的可见性 确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化. 上面的程序中NoVisibility可能会持续循环下去,因为读线程可能永远都看不到ready的值.一种更奇怪的现象是NoVisibility可能会输出0,因为读线程可能看到了写入ready的值,但却没有看到之后写入number的值,这种现象被称为"重排序".多线程之指令重排序 失效数据 简而言之就是在缺乏同步的程序中可能会读取到

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程

《Java并发编程实战》第三章 对象的共享 读书笔记

一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见性的描写叙述即多线程能够实时获取其它线程改动后的状态. *** 待补充   两个工人同一时候记录生产产品总数问题 1. 失效数据 可见性出现故障就是其它线程没有获取到改动后的状态,更直观的描写叙述就是其它线程获取到的数据是失效数据. 2. 非原子64位操作 3. 加锁与可见性 比如在一个变量的读取与