java - 如果它具有发生前的保证,那么在构造函数的最后一个语句中让“this”转义是否安全?
问题描述
Java 中的一个常见建议是在构造对象期间不要让“this”引用逃逸,因此不要在构造函数中启动任何线程。但是我发现自己编写了很多应该使用执行程序启动线程的类。根据常见的建议,我应该编写一个额外的 start() 方法,将任务提交给执行程序。
但是将任务提交给执行者会提供发生前发生的保证,如此处所述。那么在构造函数的最后一条语句中提交任务会不会好呢?或者更一般的问题:如果构造函数的最后一个语句提供发生前的保证,那么让“this”在构造函数的最后一个语句中转义是否安全?
解决方案
Stefan Feuerhahn的答案是正确的。
我将添加一个建议,即在执行工作的类中嵌入执行器服务可能是一种“代码味道”,表明设计薄弱。
通常,我们希望在设计中遵循单一责任原则。一个类应该有一个单一的目的,并且应该尽量不偏离那个狭窄的特定目的。
例如,如果编写了一个类来创建报告,那么该类应该只知道该报告。该类不应该知道应该何时运行该报告,或者运行该报告的频率,或者如果该报告已经运行,其他代码关心什么。
这种运行报告的时间安排与应用程序的生命周期相关。对于一件重要的事情,执行器服务最终必须在不再需要或应用程序退出时关闭。否则后备线程池可能会像僵尸一样无限期地继续下去。您的报告生成类不应该知道何时不再需要它,也不应该知道应用程序何时或为何退出。
问题的另一个方面是配置执行器服务涉及了解部署方案。多少 RAM、多少 CPU 内核、主机上的其他负担,都有助于决定如何设置 executor 服务。您的报告生成代码不应该因为部署情况的变化而改变。
生成报告的类不应该知道调用应用程序的生命周期,也不应该知道执行器服务。生成报告的应用程序应该只知道如何生成一份报告。代码中的其他位置,可能是某个报表管理器类或应用程序的生命周期编排代码,应该处理运行报表的频率和时间。
推荐阅读
- java - 仅更改一项微调器android的样式
- django - Nginx 不提供媒体文件。Dockerizing django/nginx/gunicorn/postgresql
- c# - ASP.NET Core 启动消息日志
- scripting - 具有多标准案例的 NSIS 交换机
- latex - 如何在 R 中迭代 kable?
- python - 使用 SciPy 在曲线之间进行插值
- node.js - 当MongoDB中至少需要一个子文档时,有什么更好的方法来防止删除所有子文档
- java - 获取最大尺寸的连续子阵列尺寸
- c - 为什么我的 flex 和 bison 程序不起作用?正弦和余弦函数计算器
- go - image.Decode 在解码 .png 文件时返回错误