代码的性能是最重要的。然而,在当今复杂的多线程移动应用世界里,我们常常会为保证内存数据的一致性而牺牲一些性能。线程竞争条件的设计和调试是一件非常耗时,且容易令人沮丧的工作,所以线程被锁定太长时间的情况并不少见。幸运的是,现在有一些简单的模式可以使锁定变得更有效率,从而避免对性能产生不必要的影响。
首先,让我们先预览一下只有简单 setter 代码的基类:
public class Foo { private Map<string, string=""> data; public Foo() { data = new HashMap<string, string="">(); } public void setData(String key, String value) { data.put(key, value); } }
在上面的代码里,每当我们实例化一个Foo对象的同时也在实例化一个HashMap对象,而无论该HashMap是否会被使用。一般情况下,在一个强劲配置的服务器上,前面实例化的开销相对较低。但是相对一个只放在你口袋里,并且整天运行在一块电池上的设备,那样子的开销将会上升得非常快。为了提升效率,我们采用懒加载策略来重写上面的代码。
public class Foo { private Map<string, string=""> data; public Foo() { } public void setData(String key, String value) { if (data == null) data = new HashMap<string, string="">(); data.put(key, value); } }
现在Foo的构造器实质上是空的构造器,而且我们只有在调用setData方法时,才会产生实例化HashMap对象的开销。在这点上,我们快速实现了只有在绝对需要的时候才去使用内存。然而这种实现的方式并非是线程安全的。线程安全是非常重要的,自从Android对线程操作的要求达到了一个根本的层面(你不可以在UI线程上执行IO阻塞的操作)。
在上面的例子中,有两个地方需要特别注意的。第一,我们需要线程安全的数据结构。使用 ConcurrentHashMap取代HashMap可以简单地解决这点。第二,稍稍复杂一点,我们需要为属性 data 的实例化,设置更微妙的竞争条件。有这样子的可能性,两个线程同时判断属性data是否为null,并尝试为其实例化。更糟糕的是,其中一个线程会对其实例化的map置入一个对象,但该map实例将会丢失,如果两一个线程也实例化了自己的map对象。为了避免这种竞争情况,我们可以为此加上 synchronized 代码块:
public class Foo { private Map<string, string=""> data; public Foo() { } public void setData(String key, String value) { synchronized (this) { if (data == null) data = new ConcurrentHashMap<string, string="">(); } data.put(key, value); } }
这就确保了同一时间里,只有一个线程进行null检查,并在需要的时候对属性data进行实例化。好像到这里,问题都迎刃而解了,然而,或许你还会记得我们的关注点是在于性能的优化,很不幸,synchronized 代码块的开销往往比较大。在这种情况下,在同一时间里,只有一个线程可以高效地访问方法setData。幸好,我们还有另一个方法可以使用:double-checked locking。在维基百科上有一篇优秀的文章对 double-checked locking 作了详尽的介绍。在我们的例子里,运用该方法后的代码如下:
public class Foo { private volatile Map<string, string=""> data; public Foo() { } public void setData(String key, String value) { if (data == null) { synchronized (this) { if (data == null) data = new ConcurrentHashMap<string, string="">(); } } data.put(key, value); } }
在上面的代码中,有两个非常重要的改变。其一,为属性data添加了volatile声明。这将指示编译器,最终是Dalvik VM,确保数据的读写操作按预读顺序(译者注:happened-before order)执行。换句话说,写数据操作,总是发生在读数据操作之前(没有这个关键字的声明,编译器或JIT优化或会使它们顺序逆转)。其次,我们在synchronized 代码块外面再添加了一层null检查。这就确保一旦属性data已被实例化,我们将不会再执行 synchronized 的代码块。然而,如果属性data确实为null,我们将 synchronize 对象,然后双重检查属性data是否为null,以确保在两次检查之间,没有其他线程没有执行属性data的实例化。如果没有这个竞争条件,代码将继续执行,继而跳出这个 synchronized 代码块。
到这里,细心而聪明的读者或许会注意到,上述方法在Java1.5之前并不是总是可靠的。Dalvik VM也是有相似的历史,使用该方法前,请从 这里 检查一下。在这里更推荐大家阅览 这篇 描述如何在Android处理内存一致性问题的优秀指南。
本文由zhiweiofli编辑发布,转载请注明出处,谢谢。
相关推荐
C++ and the Perils of Double-Checked Locking 关于单例模式C++实现的一些问题
C++ and the Perils of Double Checked Locking.zip
在做角色权限,通过tree控件展示权限列表的时候,用:default-checked-keys绑定数据,这个属性不能实现双向绑定,只能用于初始化选择状态。如果想双向绑定只能使用组件的方法setCurrentKey来实现。想直接绑定数据来的...
本文主要讲解AngularJS ng-checked 指令,在这整理ng-checked 指令的基础知识,并附代码实例,有需要的小伙伴可以参考下
本篇文章主要介绍了深究AngularJS——ng-checked(回写:带真实案例代码),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
四色定理的计算机证明,网上有coq平台和定理证明的源代码下载。
checked.css是一款能够制作复选框和单选按钮点击动画的CSS3动画库。它内置23种动画特效,在用户点击单选按钮或复选框时会出现相应的动画效果。
1.寂寞的Singleton 2. 当Singleton遇见多线程 4.安全发布 6. 讨论的延续 1. JavaWorld章:Double-checked l
多检查奇迹:checked伪类 polyfill(适用于 IE8 及以下)。如何使用包括 jQuery 1.x(与旧 IE 兼容)>= 1.7,然后在 IE 条件注释中包含 poly-checked 脚本: < script src =" //ajax.googleapis....
北京交通大学期末试卷汇编作业-checked.docx
AngularJS是当前非常的流行的前端框架,它的语法糖非常多,也极大的方便了前端开发者。这篇文章主要介绍了ng-options和ng-checked在表单中的高级运用,需要的朋友可以参考下
代码片段: function isAllChecked(){ ... allChecked = $(this).find(":checked").not("[name='all-checked']") , thisAllCheckBtn = $(this).find(".all-checked [name='all-checked']");
这个小程序涉及到了以下知识点: Java基础知识 队列《数据结构》 单例模式“双检锁/双重校验锁(DCL,即 double-checked locking)”
Software Adaptation in an Open Environment: A Software Architecture Perspective by Yu Zhou ...The organization and presentation of the book will be double-checked by professional scholars
xcx-checked 小程序:view组件 单选操作,多选操作[可限制选中的数量]... 小程序的组件checkbox,checkbox-group实现单选和多选功能是比较容易的,就是实际项目中考虑到页面美观和用户体验,还是选择自定义的,那么...
语言:English (United States) 此扩展旨在每周介绍一下柔和的轻推,提醒我们,我们的时期是有限的。 在几周内的寿命 - 检查每个盒子代表的网格 你生命中的一周。 在每周的特定时间,您都会提醒您查看下一个框以开始...
• Chapter 21: The Singleton Pattern and the Double-Checked Locking Pattern • Chapter 22: The Object Pool Pattern • Chapter 23: The Factory Method Pattern • Chapter 24: Summary of Factories (no ...
双重检测锁(Double-Checked Locking)实现的Singleton模式在多线程应用中有相当的价值。在ACE的实现中就大量使用ACE_Singleton模板类将普通类转换成具有Singleton行为的类。这种方式很好地消除了一些重复代码臭味,...