Java理论与实践:做个好的(事件)侦听器 - 编程入门网
,也不应当允许“this”引用在构 造函数中转义 —— 这样做会危害 Java 内存模型的某些安全保证。如果“this ”这个词不会出现在程序中,就可让“this”引用转义;发布一个非静态内部类 实例可以达到相同的效果,因为内部类持有对它包围的对象的“this”引用的引 用。偶然地允许“this”引用转义的最常见原因,就是登记侦听器,如清单 4 所示。事件侦听器不应当在构造函数中登记!
清单 4. 通过发布内部类实例,显式地允许“this”引用转义 侦听器线程安全 使用侦听器造成的第三个线程安全问题来自这个事实:侦听器可能想访问应 用程序数据,而调用侦听器的线程通常不直接在应用程序的控制之下。如果在 JButton 或其他 Swing 组件上登记侦听器,那么会从 EDT 调用该侦听器。侦听 器的代码可以从 EDT 安全地调用 Swing 组件上的方法,但是如果对象本身不是 线程安全的,那么从侦听器访问应用程序对象会给应用程序增加新的线程安全需 求。 Swing 组件生成的事件是用户交互的结果,但是 Swing 模型类是在 fireXxxEvent() 方法被调用的时候生成事件。这些方法又会在调用它们的线程 中调用侦听器。因为 Swing 模型类不是线程安全的,而且假设被限制在 EDT 内 ,所以对 fireXxxEvent() 的任何调用也都应当从 EDT 执行。如果想从另外的 线程触发事件,那么应当用 Swing 的 invokeLater() 功能让方法转而在 EDT 内调用。一般来说,要注意调用事件侦听器的线程,还要保证它们涉及的任何对 象或者是线程安全的,或者在访问它们的地方,受到适当的同步(或者是 Swing 模型类的线程约束)的保护。 失效侦听器 不管什么时候使用观察者模式,都耦合着两个独立组件 —— 观察者和被观 察者,它们通常有不同的生命周期。登记侦听器的后果之一就是:它在被观察对 象和侦听器之间建立起很强的引用关系,这种关系防止侦听器(以及它引用的对 象)被垃圾收集,直到侦听器取消登记为止。在许多情况下,侦听器的生命周期 至少要和被观察的组件一样长 —— 许多侦听器会在整个应用程序期间都存在。 但是在某些情况下,应当短期存在的侦听器最后变成了永久的,它们这种无意识 的拖延的证据就是应用程序性能变慢、高于必需的内存使用。 “失效侦听器”的问题可以由设计级别上的不小心造成:没有恰当地考虑包 含的对象的寿命,或者由于松懈的编码。侦听器登记和取消登记应当结对进行。 但是即使这么做,也必须保证是在正确的时间执行取消登记。清单 5 显示了会 造成失效侦听器的编码习惯的示例。它在组件上登记侦听器,执行某些动作,然 后取消登记侦听器: 清单 5. 有造成失效侦听器风险的代码 Java理论与实践:做个好的(事件)侦听器(3)时间:2010-12-20 IBM Brian Goetz清单 5 的问题是:如果文件处理代码抛出了 IOException —— 这是很有可 能的 —— 那么侦听器就永远不会取消登记,这就意味着它永远不会被垃圾收集 。取消登记的操作应当在 finally 块 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |