zoukankan      html  css  js  c++  java
  • JAVA并发编程学习笔记------对象的可见性及发布逸出

    一、非原子的64位操作:

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

      因此,即使不考虑失效数据问题,在多线程中使用共享且可变的long,double等类型的变量也是不安全的,除非用关键字volatile来声明它们,或者用锁保护起来。

    二、volatile变量

      当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量时共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
      volatile局限在于:它通常用于某个操作完成、发生中断或者状态的标志,其语义不足以确保递增操作的原子性,除非你能确保只有一个线程对变量执行写操作。
      当且仅当满足以下条件时,才应该使用volatile变量:
      1)对变量的写入操作不依赖变量的当前值,或者能确保只有单个线程更新变量的值;
      2)该变量不会与其他状态变量一起纳入不变性条件中;
      3)在访问变量时不需要加锁。

      加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。

    三、对象的发布逸出

    如下示例代码:

    public class ThisEscape {
        public ThisEscape(EventSource source) {
            source.registerListener{
                new EventListener()(){
                    public void onEvent(Event e){
                        doSomething(e);
                    }
                }
            }
        }
    }
    

      这个类不是安全的,因为当ThisEscape发布EventListener时,也隐含的发布了ThisEscape实例本身,因为这个内部类的实例中包含了对ThisEscape实例的隐含应用,因此,当从对象的构造函数中发布对象时,只是发布了一个尚未构造完成的对象。即使发布对象的语句位于构造函数的最后一行也是如此。在构造函数中创建线程并没有错误,但最好不要立即启动它,而是通过一个start或initialize方法来启动,例如,可通过如下工厂方法来防止this引用在构造过程中逸出:

    public class SafeListener {
        private static final EventListener listener;
        public SafeListener() {
            listener = new EventListener() {
                public void onEvent(Event e){
                    doSomeThing(e);
                }
            }
        }
        public static SafeListener newInstance(EventSource source){
            SafeListener safe = new SafeListener();
            source.registerListener(safe.listener);
            return safe;
        }
    }
    

      

  • 相关阅读:
    Saltstack module acl 详解
    Saltstack python client
    Saltstack简单使用
    P5488 差分与前缀和 NTT Lucas定理 多项式
    CF613D Kingdom and its Cities 虚树 树形dp 贪心
    7.1 NOI模拟赛 凸包套凸包 floyd 计算几何
    luogu P5633 最小度限制生成树 wqs二分
    7.1 NOI模拟赛 dp floyd
    springboot和springcloud
    springboot集成mybatis
  • 原文地址:https://www.cnblogs.com/hunterCecil/p/5727913.html
Copyright © 2011-2022 走看看