Java理论与实践: 消除bug - 编程入门网
些严重的问题。从那时起,允许 this 引用逃避构造的风 险变得越来越严重。如果允许对象的引用逃避其构造函数,新的 Java Memory Model(如 JSR 133 所指定,并由 JDK 1.5 实现的)抵消了所有初始化安全保 证。
对象的引用可以以几种方式逃避它的构造函数,直接和简接都可以。绝对不 可以将 this 引用保存在静态变量或数据结构中,但是有更微妙的方式允许引用 逃避构造,如公布对非静态内部类的引用,或者从构造函数中启动一个线程(这 几乎总是公布对新线程的引用)。FindBugs 有一个检测器,用于寻找从构造函 数启动线程的实例,虽然目前它不能检测所有这些危险,但是未来的版本很可能 包括用于其他初始化安全模式的检测器。 Java理论与实践: 消除bug(3)时间:2010-12-20 IBM Brian Goetz为内存模型带来好处 在“ 修复 Java 内存模型,第 1 部分”中,我回顾了同步的基本规则:只 要读取可能由其他线程写入的变量,或者写入随后由其他线程读取的变量,就必 须进行同步。很容易“忘记”这个规则,特别是在读取时 —— 但是这么做可以 造成很多有关程序线程安全的风险。这种 bug 通常是在维护类时引入的:这个 类原来是正确同步的,但是维护人员并没有完全理解线程安全需求。 幸运的是,FindBugs 拥有大量的检测器,它们可以帮助识别错误同步的类。 Inconsistent Synchronization 检测器很可能是 FindBugs 所使用的最复杂的 检测器;它必须分析整个程序,而不仅仅是单个方法,使用数据流分析来确定什 么时候加锁,并使用直观推断来推出一个类想要提供线程安全保证。基本上,对 于每个域,它都会查看该域的访问模式,并且如果大多数访问都是同步实现的, 那么没有同步的访问将被标记为可能的错误。类似地,如果一个属性的设置函数 是同步的,而获取函数不是,那么 Inconsistent Synchronization 检测器将生 成一条警告。 除了 inconsistent synchronization 之外,FindBugs 还包含其他很多用于 检测常见线程错误的检测器,如在加锁两次的情况下等待监视器(这虽然不一定 是 bug,但是可能导致死锁),使用双检测加锁模式,不正确地初始化非易失性 的域,对线程调用 run() 而不是启动线程,从构造函数中调用 Thread.start() ,或者没有将 wait() 包装到循环中就调用它。 变化,或不变化 在“ 变还是不变?”(和其他文章中),我赞扬了不可变的优点,不可变对 象不能进入不稳定的状态。它们在本质上就是线程安全的(假设它们的不可变性 是通过使用 final 关键字保证的),并且您可以随意共享和缓存对不可变对象 的引用,而不必复制或者克隆它们。 Java 语言中包括 final 关键字是为了帮助开发人员创建不可变类,并允许 编译器和运行时环境以声明的不可变性为基础进行优化。然而,虽然域可以是 final,但是数组元素不可以。通过正确地使用 final 和 private 域,可以使 对象成为不可变的,但是如果对象的状态包括数组,那么防止对这些内部数组的 引用逃避该类的方法是很重要的。清单 4 展示的类尝试成为不可变的,但是不 是,因为在调用 getStates() 之后,调用者可以修改状态数组。(相关的可能 bug 是在可变类可能返回可变数组的引用时,并且在调用者使用这个数组时,它 的内容可能已经更改了。)虽然通常将其看作一种“恶意代码”脆弱性(并且很 多开发人员并不关心“恶意代码”,因为他们的系统并不加载“不受信任”的类 ),但是这种习惯仍然可能导致各种与恶意代码无关的问题。返回一个不可修改 的 List 或者在返回之前克隆该数组可能更好。FindBugs 可以检测类似 getStates() 中的错误(如清单 4 所示)—— 虽然它不必知 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |