第三章-对象的共享

1、可见性:

多线程中,一个线程对状态变量的修改对其它线程可见。

非原子的64位操作

最低安全性:线程在没有同步的情况下读取变量时,可能会得到一个失效的值,但至少这个值是由之前某个线程设置的值,而不是一个随机的值。

最低安全性适用于绝大多数变量,但是存在一个例外,非volatile类型的64位数值变量 double和long

java内存模型要求,变量的读取和写入操作都必须是原子操作但是对非volatile的double和longJVM允许将64位的读或写操作分解位两个32位操作。当读取一个非voila提了类型的long变量时,如果对该变量的都和写在不同的线程中执行,那么狠可能会读取到某个值的高32位和另一个值的低32位。

2、Volatile变量

java提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器活着对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。在访问olatile变量时不会执行枷锁操作,银子也就不会使执行现成阻塞,因此olatile变量是种比sychronized关键字更轻量级的同步机制。

仅当olatile变量能简化代码的实现方式一击对同步策略的验证时,才应该使用他们。如果在验证正确性时需要对可见性进行复杂的判断,那么就不要使用valatile变量。volatile变量的正确使用方式包括:确保他们自身状态的可见性,确保他们所引用对象的状态的可见性,遗迹表示一些重要的程序生命周期时间的发生。

 仅当:满足一下所有条件是,才应该使用volatile变量:

  • 对变量的写入操作不依赖变量的当前值,活着你能确保只有单个现成更新变量的值。
  • 该变量不会与其他状态变量一起纳入不变性条件中
  • 在访问变量时不需要加锁。
3、发布与逸出    发布(publish)一个对象的意思是指,使对象能够在当前作用于之外的代码中使用。    逸出(Escape)当某个不应该被发布的对象被发布时这种情况就叫逸出。   当某个对象逸出后,你必须假设该对象被误用,这是使用封装的主要原因:封装能够使得对程序的正确性进行分析变得可能,并使得无意中破坏设计约束条件变得更难。  隐式的this引用逸出 这个看了好久才看明白是怎么意思。下面上书中代码:
public class ThisEscape{
 
      public ThisEscape(EventSource eventSource){

             source.registerListener(new EventListener(){

                    public void onEvent(Event e){
                          doSomething(e);
                    }

             });

      }

}
  这样如果要通过ThisEscape把EventListener注册到EventSource里面的话,就会执行这么一个操作 new ThisEscape(eventSource);   这个操作会返回一个ThisEscape对象。这样的话在发布EventListener的时候,实际也发布了一个ThisEscape对象,那么这个ThisEscape对象就已经逸出了。
  书中对this引用逸出是这样解释的:(看书一定要细看,我就犯了这个错误,有部分没注意,结果这个概念纠结了好久)     仅当对象的构造函数返回时,对象才处于一个可预测的和一只的状态,因此当从对象的构造函数中发布对象时,只是发布了一个尚未构造完成的对象。即使发布对象的语句位于构造函数的最后一行也是如此。如果this应用在构造过程中逸出,那么这种对象就被认为是不正确构造。 下面是书中修改后的代码:上
public class SafeListener{
    priavte 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;

    }

}
 上例可以看到需要注册的listener被声明为了final,并且SafeListener的构造方法被声明成了private,然后通过了一个静态的对象工厂来实例化SafeListener和注册这个EventListener;

猜你喜欢

转载自710173455.iteye.com/blog/2204190