3 对象的共享

作者: 史小猿 | 来源:发表于2018-09-11 15:27 被阅读3次

3.1可见性

加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步

Volatile变量

当把变量定义为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者其他处理器不可见的地方,因此在读取volatile类型的变量总是会返回最新写入的值。

写入volatile变量相当于退出同步代码块,读取volatile变量相当于进入同步代码块

加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
当且仅当满足以下所有条件时,才应该使用volatile变量:

  • 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
  • 该变量不会与其他状态变量一起纳入不变性条件中。
  • 在访问变量时不需要加锁

3.2发布与逸出
隐式this逸出和安全的对象构造的例子

/**
 * ThisEscape
 * <p/>
 * Implicitly allowing the this reference to escape
 *
 * @author Brian Goetz and Tim Peierls
 */
public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        });
    }

    void doSomething(Event e) {
    }


    interface EventSource {
        void registerListener(EventListener e);
    }

    interface EventListener {
        void onEvent(Event e);
    }

    interface Event {
    }
}

利用final和工厂来防止this逸出


/**
 * SafeListener
 * <p/>
 * Using a factory method to prevent the this reference from escaping during construction
 *
 * @author Brian Goetz and Tim Peierls
 */
public class SafeListener {
    private final EventListener listener;

    private 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;
    }

    void doSomething(Event e) {
    }


    interface EventSource {
        void registerListener(EventListener e);
    }

    interface EventListener {
        void onEvent(Event e);
    }

    interface Event {
    }
}

不过本人看了这个,还是不懂咋回事,不懂为什么this逸出了,参考了博客写了下边的例子就知道咋回事了

public class ThisEscape {
   private String name = null;

   public ThisEscape(EventSource source) {
       source.registerListener(new EventListener() {
           public void onEvent(Event e) {
               doSomething(e);
           }
       });
       name = "TEST";
   }

   void doSomething(Event e) {
       System.out.println(this.name.toString());
   }

   interface EventSource {
       void registerListener(EventListener e);
   }

   interface EventListener {
       void onEvent(Event e);
   }

   interface Event {
   }

   public static void main(String[] args) {
       EventSource e = new EventSource() {
           public void registerListener(EventListener e) {
               e.onEvent(null);
           }
       };
       new ThisEscape(e);
   }
}

执行结果


public class SafeListener {
    private final EventListener listener;
    private String name = null;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
        name = "TEST";
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }

    void doSomething(Event e) {
        System.out.println(this.name.toString());
    }
    interface EventSource {
        void registerListener(EventListener e);
    }

    interface EventListener {
        void onEvent(Event e);
    }

    interface Event {
    }
    public static void main(String[] args) throws InterruptedException {
        EventSource es = new EventSource(){
            public void registerListener(EventListener e){
                e.onEvent(null);
            }
        };
        //        new ThisEscape(es);
        SafeListener.newInstance(es);
    }


}

执行结果



第一个例子,类没有初始化完全,就使用this 报了空指针异常,this逸出。
第二个例子,类完全初始化后,使用this 正常打印。

3.3线程封闭(todo)
例子 JDBC Connection,Swing
栈封闭
引用被封闭在了方法中
ThreadLocal类

相关文章

  • 3 对象的共享

    3.1可见性 加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行...

  • 3.对象的共享

    1.写在最前面 第二章中可以使用同步来 避免 多个线程在同一时刻访问相同的数据(使用了同步访问共享数据就需要排队,...

  • Apex的对象共享

    Apex的对象共享 在Apex中,每个对象都有一个“共享”对象,其中存储了该对象的共享设定。 这种共享对象以“sh...

  • 并发编程-3 对象的共享

    同步的作用 1、确保以原子的方式执行操作:防止读取正在被修改的状态变量 2、 内存可见性:确保一个线程修改了对象状...

  • 3对象共享

    同步的作用 确保复合操作的原子性(复合操线程间作互斥) 内存可见性 volatile 作用:将当前线程对volat...

  • Python设计模式 - 共享模式

    """ 共享模式:共享对象,避免内存浪费(避免重复创建相同对象) """ #共享模式 classBorg: """...

  • 对象的共享

    synchronized不仅可以保证原子性,确定临界区,还可以保证可见性 1.可见性 1.1失效数据 如果对象无法...

  • 对象的共享

    对象的共享 在上一篇线程安全的总结中,说到了要想编写正确的并发程序,关键在于:在访问共享的可变状态时需要进行正确的...

  • R Ubuntu 找不到libRlapack.so

    【ERROR】:无法载入共享目标对象‘/mnt/Storage/home/usr/miniconda3/lib/R...

  • java基础专题:5. 如何实现线程安全

    1.不共享变量,或者共享不可变对象(String,Long,Double,BIgDecimal,或者对对象的所有属...

网友评论

    本文标题:3 对象的共享

    本文链接:https://www.haomeiwen.com/subject/xfpjgftx.html