zoukankan      html  css  js  c++  java
  • Java并发编程(五):Java线程安全性中的对象发布和逸出

    发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系。

    什么是发布?简单来说就是提供一个对象的引用给作用域之外的代码。比如return一个对象,或者作为参数传递到其他类的方法中。

    什么是逸出?如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性。

    概念我们知道了,可我们要关注什么地方呢?我们要关注的时候就是逸出问题,在不该发布该对象的地方就不要发布该对象,例如以下代码:

    复制代码
    1 class UnsafeStates{
    2     private String[] states = new String[]{"AK", "AL"};
    3 
    4     public String[] getStates(){
    5         return states;
    6     }
    7 }
    复制代码

    states变量作用域是private而我们在getStates方法中却把它发布了,这样就称为数组states逸出了它所在的作用域。

    然而更加隐蔽和需要我们注意的是this逸出,这个问题要引起重点关注。什么是this逸出?观察以下代码:

    复制代码
     1 public class ThisEscape{
     2     private int value;
     3     public ThisEscape(EventSource source){
     4         source.registerListener{
     5             new EventListener(){
     6                 public void onEvent(Event e){
     7                     doSomething(e);
     8                 }
     9             }
    10         }
    11         //一些初始化工作
    12         value = 7;    
    13     }
    14 
    15     public void doSomething(Event e){
    16         System.out.println(value);
    17     }
    18 
    19 }
    复制代码

    在构造方法中我们定义了一个匿名内部类,匿名内部类是一个事件监听类,当事件监听类注册完毕后,实际上我们已经将EventListener匿名内部类发布出去了,而此时我们实际上已经携带了this逸出,重点在于这个时候我们还有一些初始化工作没有做完(代码11行之后),这也就是上面所说的,一个类还没有构造结束我们已经将发布了。那怎么来避免this逸出呢?既然我们没有构造完构造函数,那我们就将构造函数构造完嘛,将构造函数定义为private作用域。如以下代码所示:

    复制代码
     1 public class SafeListener{
     2     private final EventListener listener;
     3 
     4     private safeListener(){
     5         listener = new EventListener(){
     6             public void onEvent(Event e){
     7                 doSomething(e);
     8             }
     9         }
    10     }
    11 
    12     public static SafeListener newInstance(EventSource source){
    13         SafeListener safeListener = new SafeListener();
    14         safeListener.registerListener(safeListener.listener);
    15 
    16         return safeListener;
    17     }
    18 }
    复制代码

    我们首先将构造函数设定为private,其次我们在构造函数未完成时不将对象进行发布,而是使用工厂方法,在工厂方法newInstance中待构造函数执行完毕后再将对象进行发布(代码中即为registenerListener注册监听)。这实际上就是修改为了构造完毕->发布对象的串行执行模式,而不是之前的异步模式,这样就不会给我们带来线程安全性的问题。

  • 相关阅读:
    android编译时出现org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileDebugJavaWithJavac'.错误
    jdk1.8中获取项目绝对路径和项目路径
    okhttp在https连接中出现java.net.ProtocolException: Expected ':status' header not present的解决办法
    mybatis+sqlserver中返回非自增主键
    华为手机不能连接android studio进行调试的解决办法
    android中service启动后台程序
    getContentLength() 指为 -1 的解决办法
    svn服务器搭建(windows)
    Caliburn.Micro 杰的入门教程3,事件和参数
    Caliburn.Micro 杰的入门教程1(翻译)
  • 原文地址:https://www.cnblogs.com/shamo89/p/9069295.html
Copyright © 2011-2022 走看看