当前位置: 首页 > news >正文

Java并发编程(六)发布与逸出

 

"发布(Publish)"一个对象的意思指,使对象能够在作用域之外的代码中使用。

 

例如:

将一个指向该对象的引用保存到其他代码可以访问的地方

在一个非私有的方法中返回该引用

将引用传递到其他类的方法中

 

有时候要确保对象及其内部状态不被发布,但是某些情况下又需要发布。

 

如果在发布时要确保线程安全性,则可能需要同步。

 

发布内部状态可能会破坏封装性,并使得程序难以维持不变性条件。

 

比如在对象构造完成之前就发布该对象,就会破坏线程安全性。

 

 

当某个不应该被发布的对象被发布时,这种情况就叫做"逸出"。

 

逸出的例子:

 

public class PublishDemo {
    public static Set<Integer> intSet;
    
    public void initialize() {
        intSet = new HashSet<>();
    }
}

在发布某个对象的时候,可能会间接发布其他对象。比如上面代码中的不仅Set这个集合会被发布出去,Set中的Integer对象也会被发布出去。

 

public class UnsafeStates {
    private String[] states = new String[] {"AK", "47"};

    public String[] getStates() {
        return states;
    }
}

 

简而言之,就是本来一个人可以经手处理的事情,现在搞得n多个人都可以插上一手了,你说安全不安全。当某个对象逸出之后,必须要假设某个类或者线程会误用该对象。这正是需要封装的原因:封装能够使得对程序的正确性进行分析变得可能,并使得无意中破坏设计约束条件变得更难。

 

还有一种发布对象或其内部状态的机制就是发布一个内部的类实例。

public class PublishInnerClass {

    public PublishInnerClass(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    System.out.println("heheda");
                }
            }
        );
    }

    class EventSource {
        public void registerListener(EventListener eventListener) {
            // 暴露出去了
        }
    }
}

不要在构造过程中使this逸出。

 

在构造过程中使this引用逸出的一个常见错误是,在构造函数中启动一个线程。当对象在其构造函数中创建一个线程时,无论是显式创建(通过将它传递给构造函数)还是隐式创建(由于Thread或Runnable是该对象的一个内部类),this引用都会被新创建的线程共享。

 

在对象尚未完全构造之前,新的线程就可以看见她。在构造函数中创建线程并没有错误,但最好不要立即启动它,而是通过一个start或initialize方法启动。在构造函数中调用一个可改写的实例方法时(既不是私有方法,也不是终结方法),同样会导致this引用在构造过程中逸出。

 

新技能

 

如果想在构造函数中注册一个事件监听器或启动线程,那么可以使用一个私有构造函数和一个公共的工厂方法(Factory Method),从而避免不正确的构造过程。

 

public class SafeListener {
    private final EventListener listener;
    private SafeListener() {
        listener = new EventListener() {

            public void onEvent(Event e) {
                System.out.println("呵呵哒");
            }

        };
    }

    class EventSource {
        public void registerListener(EventListener listener) {

        }
    }

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

 

结论一:当注册的事件监听器监听到某一个事件发生时,会启用一个新的线程去执行相关的事情。(这个我们在代码中手动启动了一个线程来模拟,在没有监听器注册的时候,启动的线程会自动的阻塞!)
结论二:在外部内中初始化一个内部类的对象时,此内部类的对象保留了一个外部内对象的一个引用。这是java自带的一个机制,这在java中这种机制叫做"synthetic"。通过断点调试我们可以清晰的看到这种实现。

相关文章:

  • linux 查看网卡流量的方法
  • 自己制作 XP With SP3 系统光盘 包括驱动SATA集成AHCI驱动
  • 使用Maven运行单元测试
  • 创建服务
  • python01 用户交互程序
  • Mongodb 3.2 Manual阅读笔记:CH9 存储
  • 第101天:CSS3中transform-style和perspective
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • RxJS: 简单入门
  • 使用秘钥登录服务器
  • JavaScript学习(1)之JavaScript基础
  • 依赖倒置原则(Dependency Inversion Principle)
  • 物联网下的工控机产业发展迅速 潜力正不断被挖掘
  • 列表与元组的区别
  • Linux下curl命令的使用
  • 2017前端实习生面试总结
  • Apache Spark Streaming 使用实例
  • cookie和session
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • leetcode98. Validate Binary Search Tree
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • React Transition Group -- Transition 组件
  • spark本地环境的搭建到运行第一个spark程序
  • spring + angular 实现导出excel
  • SQLServer之索引简介
  • Vue2 SSR 的优化之旅
  • vue总结
  • 小程序测试方案初探
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • $refs 、$nextTic、动态组件、name的使用
  • (007)XHTML文档之标题——h1~h6
  • (1)(1.11) SiK Radio v2(一)
  • (13):Silverlight 2 数据与通信之WebRequest
  • (C语言)字符分类函数
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转载)OpenStack Hacker养成指南
  • .mysql secret在哪_MYSQL基本操作(上)
  • .net core 6 集成和使用 mongodb
  • .NET 依赖注入和配置系统
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .Net6 Api Swagger配置
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET开源快速、强大、免费的电子表格组件
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [ 数据结构 - C++] AVL树原理及实现
  • [AR Foundation] 人脸检测的流程
  • [c++] 自写 MyString 类