ConcurrentHashMap和CopyOnWriteArrayList提供线程安全性和已改进可伸缩性 .docx

上传人:C****o 文档编号:13044502 上传时间:2022-04-27 格式:DOCX 页数:9 大小:81.31KB
返回 下载 相关 举报
ConcurrentHashMap和CopyOnWriteArrayList提供线程安全性和已改进可伸缩性 .docx_第1页
第1页 / 共9页
ConcurrentHashMap和CopyOnWriteArrayList提供线程安全性和已改进可伸缩性 .docx_第2页
第2页 / 共9页
点击查看更多>>
资源描述

《ConcurrentHashMap和CopyOnWriteArrayList提供线程安全性和已改进可伸缩性 .docx》由会员分享,可在线阅读,更多相关《ConcurrentHashMap和CopyOnWriteArrayList提供线程安全性和已改进可伸缩性 .docx(9页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、精品名师归纳总结eJava 理论与实践 : 并发集合类ConcurrentHashMap和 CopyOnWriteArrayList供应线程安全性和已改进的可伸缩性级别: 初级Brian Goetz brian, 首席顾问 , Quiotix Corp 2003年 9 月 28 日DougLea的 util.concurrent包除了包含许多其他有用的并发构造块之外, 仍包含了一些主要集合类型 List和 Map 的高性能的、线程安全的实现. 在本月的 Java 理论与实践中,BrianGoetz向您呈现了用ConcurrentHashMap替换 Hashtable或 synchronized

2、Map, 将有多少并发程序获益 .您可以在本文的 论坛中与作者以及其他读者共享您的想法(您也可以点击文章顶部或者底部的 争辩进入论坛) .在 Java 类库中显现的第一个关联的集合类是 Hashtable , 它是 JDK 1.0 的一部分 . Hashtable 供应了一种易于使用的、线程安全的、关联的 map 功能, 这当然也是便利的 .然而, 线程安全性是凭代价换来的 Hashtable 的全部方法都是同步的 . 此时, 无竞争的同步会导致可观的性能代价. Hashtable的后继者 HashMap 是作为 JDK1.2中的集合框架的一部分显现的, 它通过供应一个不同步的基类和一个同步的

3、包装器Collections.synchronizedMap, 解决了线程安全性问题 . 通过将基本的功能从线程安全性中分别开来, Collections.synchronizedMap答应需要同步的用户可 以拥有同步 , 而不需要同步的用户就不必为同步付出代价.Hashtable和 synchronizedMap所实行的获得同步的简洁方法(同步Hashtable中或者同步的Map 包装器对象中的每个方法)有两个主要的不足. 第一, 这种方法对于可伸缩性是一种障碍, 由于一次只能有一个线程可以拜望hash 表. 同时, 这样仍不足以供应真正的线程安全性, 许多公用的混合操作仍然需要额外的同步

4、.虽然诸如 get和 put之类的简洁操作可以在不需要额外同步的情形下安全的完成 , 但仍是有一些公用的操作序列, 例如迭代或者put-if-absent(空就放入) , 需要外部的同步, 以防止数据争用 .有条件的线程安全性同步的集合包装器 synchronizedMap和 synchronizedList, 有时也被称作有条件的线程安全 全部单个的操作都是线程安全的, 但是多个操作组成的操作序列却可能导致数据争用, 由于在操作序列中把握流取决于前面操作的结果.清单 1 中第一片段呈现了公用的put-if-absent语句块 假如一个条目不在Map 中, 那么添加这个条目 . 不幸的是 ,

5、在 containsKey方法返回到put方法被调用这段时间内 , 可能会有另一个线程也插入一个带有相同键的值. 假如您想确保只有一次插入 , 您需要用一个对 Map m 进行同步的同步块将这一对语句包装起来.清单 1 中其他的例子与迭代有关. 在第一个例子中 , List.size的结果在循环的执行期间可能会变得无效 , 由于另一个线程可以从这个列表中删除条目. 假如时机不得当 , 在刚好进入循环的最终一次迭代之后有一个条目被另一个线程删除了, 就 List.get将返回 null, 而 doSomething就很可能会抛出一个NullPointerException反常. 那么,实行什么措

6、施才能防止这种情形了?假如当您正在迭代一个 List时另一个线程也可能正在拜望这个List, 那么在进行迭代时您必需使用一个synchronized块将这个 List包装起来 , 在 List1 上同步 , 从而锁住整个 List. 这样做虽然解决了数据争用问题 , 但是在并发性方面付出了更多的代价, 由于在迭代期间锁住整个List会堵塞其他线程, 使它们在很长一段时间内不能拜望这个列表.集合框架引入了迭代器 ,用于遍历一个列表或者其他集合, 从而优化了对一个集合中的元素进行迭代的过程 . 然而, 在 java.util集合类中实现的迭代器极易崩溃, 也就是说 , 假如在一个线程正在通过一个

7、Iterator遍历集合时 ,另一个线程也来修改这个集合, 那么接下来的 Iterator.hasNext或可编辑资料 - - - 欢迎下载精品名师归纳总结Iterator.next调用将抛出 ConcurrentModificationException反常. 就拿刚才这个例子来讲, 假如想要防止显现ConcurrentModificationException反常, 那么当您正在进行迭代时 , 您必需使用一个在 List l上同步的 synchronized块将该 List包装起来 , 从而锁住整个List. (或者, 您也可以调用 List.toArray, 在不同步的情形下对数组进行迭

8、代, 但是假如列表比较大的话这样做代价很高) .清单 1.同步的 map中的公用竞争条件Map m = Collections.synchronizedMapnew HashMap List l = Collections.synchronizedListnew ArrayList/ put-if-absent idiom - contains a race condition/ may require external synchronization if .map.containsKeykey。map.putkey, value。/ ad-hoc iteration - contains

9、race conditions/ may require external synchronizationfor int i=0。 ilist.size。 i+ doSomethinglist.geti。/ normal iteration - can throw ConcurrentModificationException/ may require external synchronizationfor Iterator i=list.iterator doSomethingi.next。 i.hasNext。 。信任的错觉synchronizedList和 synchronizedMap

10、供应的有条件的线程安全性也带来了一个隐患开发者会假设 , 由于这些集合都是同步的 , 所以它们都是线程安全的 , 这样一来他们对于正确的同步混合操作这件事就会疏忽 .其结果是尽管表面上这些程序在负载较轻的时候能够正常工作, 但是一旦负载较重, 它们就会开头抛出NullPointerException或 ConcurrentModificationException.可伸缩性问题可伸缩性指的是一个应用程序在工作负载和可用处理资源增加时其吞吐量的表现情形. 一个可伸缩的程序能够通过使用更多的处理器、内存或者I/O带宽来相应的处理更大的工作负载.锁住某个共享的资源以获得独占式的拜望这种做法会形成可伸

11、缩性瓶颈 它使其他线程不能拜望那个资源, 即使有闲暇的处理器可以调用那些线程也无济于事. 为了取得可伸缩性 ,我们必需排除或者削减我们对独占式资源锁的依靠 .同步的集合包装器以及早期的Hashtable和 Vector类带来的更大的问题是 , 它们在单个的锁上进行同步 . 这意味着一次只有一个线程可以拜望集合, 假如有一个线程正在读一个Map, 那么全部其他想要读或者写这个 Map 的线程就必需等待 . 最常见的 Map 操作,get和 put, 可能比表面上要进行更多的处理 当遍历一个 hash 表的 bucket以期找到某一特定的key 时,get必需对大量的 候选 bucket调用 Ob

12、ject.equals. 假如 key 类所使用的 hashCode函数不能将 value均匀的分布在整个 hash表范畴内 , 或者存在大量的 hash 冲突, 那么某些 bucket链就会比其他的链长很 多, 而遍历一个长的 hash 链以及对该 hash链上确定百分比的元素调用equals是一件很慢的 事情. 在上述条件下 , 调用 get和 put的代价高的问题不仅仅是指拜望过程的缓慢, 而且, 当有线程正在遍历那个hash链时, 全部其他线程都被锁在外面, 不能拜望这个 Map.(哈希表依据一个叫做hash的数字关键字( key )将对象储备在 bucket中.hash value是

13、从对象中的值运算得来的一个数字. 每个不同的 hash value都会创建一个新的 bucket.要查找一个对象, 您只需要运算这个对象的hash value并搜寻相应的 bucket就行了 . 通过快速的找到相应的可编辑资料 - - - 欢迎下载精品名师归纳总结bucket,就可以削减您需要搜寻的对象数量了. 译者注)get执行起来可能会占用大量的时间, 而在某些情形下 , 前面已经作了争辩的有条件的线程安全性问题会让这个问题变得仍要糟糕得多.清单 1 中演示的争用条件常常使得对单个集合的锁在单个操作执行完毕之后仍必需连续保持一段较长的时间. 假如您要在整个迭代期间都保持对集合的锁,那么其他

14、的线程就会在锁外停留很长的一段时间, 等待解锁 .实例:一个简洁的 cacheMap 在服务器应用中最常见的应用之一就是实现一个cache.服务器应用可能需要缓存文件内容、 生成的页面、数据库查询的结果、与经过解读的XML 文件相关的 DOM 树, 以及许多其他类型的数据.cache的主要用途是重用前一次处理得出的结果以削减服务时间和增加吞吐量.cache工作负载的一个典型的特点就是检索大大多于更新,因此(理想情形下) cache能够供应特殊好的 get性能. 不过, 使用会阻碍性能的 cache仍不如完全不用 cache.假如使用 synchronizedMap来实现一个 cache, 那么

15、您就在您的应用程序中引入了一个潜在的可伸缩性瓶颈 . 由于一次只有一个线程可以拜望Map, 这些线程包括那些要从Map 中取出一个值的线程以及那些要将一个新的 key, value对插入到该 map 中的线程 .减小锁粒度提高 HashMap 的并发性同时仍供应线程安全性的一种方法是废止对整个表使用一个锁的方式, 而接受对 hash 表的每个 bucket都使用一个锁的方式(或者, 更常见的是 , 使用一个锁池 , 每个锁负责爱惜几个 bucket). 这意味着多个线程可以同时的拜望一个Map 的不同部分 , 而不必争用单个的集合范畴的锁 . 这种方法能够直接提高插入、检索以及移除操作的可伸缩

16、性.不幸的是 , 这种并发性是以确定的代价换来的 这使得对整个集合进行操作的一些方法(例如size或 isEmpty)的实现更加困难 , 由于这些方法要求一次获得许多的锁, 并且仍存在返回不正确的结果的风险. 然而, 对于某些情形 , 例照实现 cache, 这样做是一个很好的折衷 由于检索和插入操作比较频繁, 而 size 和 isEmpty操作就少得多 .可编辑资料 - - - 欢迎下载精品名师归纳总结ConcurrentHashMaputil.concurrent包中的 ConcurrentHashMap类(也将显现在 JDK 1.5中的回页首可编辑资料 - - - 欢迎下载精品名师归纳

17、总结java.util.concurrent包中)是对Map 的线程安全的实现 , 比起 synchronizedMap来, 它供应了好得多的并发性 . 多个读操作几乎总可以并发的执行, 同时进行的读和写操作通常也能并发的执行, 而同时进行的写操作仍然可以不时的并发进行(相关的类也供应了类似的多个读线程的并发性, 但是, 只答应有一个活动的写线程). ConcurrentHashMap被设计用来优化检索操作。实际上, 成功的get操作完成之后通常根本不会有锁着的资源. 要在不使用锁的情形下取得线程安全性需要确定的技巧性 , 并且需要对 Java 内存模型( Java Memory Model)

18、的细节有深化的理解. ConcurrentHashMap实现, 加上 util.concurrent包的其他部分 , 已经被争辩正确性和线程安全性的并发专家所正视 .在下个月的文章中 , 我们将看看ConcurrentHashMap的实现的细节 .ConcurrentHashMap通过略微的放松它对调用者的承诺而获得了更高的并发性. 检索操作将可以返回由最近完成的插入操作所插入的值,也可以返回在步调上是并发的插入操作所添加的值(但是决不会返回一个没有意义的结果).由 ConcurrentHashMap.iterator返回的 Iterators将每次最多返回一个元素 ,并且决不会抛出Concu

19、rrentModificationException反常, 但是可能会也可能不会反映在该迭代器被构建之后发生的插入操作或者移除操作. 在对集合进行迭代时 ,不需要表范畴的锁就能供应线程安全性 . 在任何不依靠于锁整个表来防止更新的应用程序中, 可以使用ConcurrentHashMap来替代 synchronizedMap或 Hashtable.上述改进使得 ConcurrentHashMap能够供应比 Hashtable高得多的可伸缩性 , 而且, 对于许多类型的公用案例(比如共享的cache )来说 , 仍不用缺失其效率 .好了多少?表 1 对 Hashtable和 ConcurrentH

20、ashMap的可伸缩性进行了粗略的比较. 在每次运行过程中 , n 个线程并发的执行一个死循环, 在这个死循环中这些线程从一个Hashtable或者ConcurrentHashMap中检索随机的 key value,发觉在执行 put操作时有 80% 的检索失败率 ,可编辑资料 - - - 欢迎下载精品名师归纳总结在执行操作时有1% 的检索成功率 .测试所在的平台是一个双处理器的Xeon系统, 操作系统是Linux. 数据显示了 10,000,000次迭代以毫秒计的运行时间, 这个数据是在将对ConcurrentHashMap的 操作标准化为一个线程的情形下进行统计的. 您可以看到 , 当线程

21、增加到多个时, ConcurrentHashMap的性能仍然保持上升趋势, 而 Hashtable的性能就随着争用锁的情形的显现而马上降了下来.比起通常情形下的服务器应用, 这次测试中线程的数量看上去有点少. 然而, 由于每个线程都在不停的对表进行操作 , 所以这与实际环境下使用这个表的更多数量的线程的争用情形基本等同.表 1.Hashtable与 ConcurrentHashMap在可伸缩性方面的比较线程数ConcurrentHashMapHashtable11.001.0322.5932.4045.5878.23813.21163.481627.58341.213257.27778.41C

22、opyOnWriteArrayList在那些遍历操作大大的多于插入或移除操作的并发应用程序中, 一般用 CopyOnWriteArrayList类替代 ArrayList. 假如是用于存放一个侦听器(listener)列表 , 例如在 AWT 或 Swing应用程序 中, 或者在常见的 JavaBean中,那么这种情形很常见(相关的CopyOnWriteArraySet使用一个CopyOnWriteArrayList来实现 Set 接口) .假如您正 在使用一个一般的 ArrayList来存放一个侦听器列表 , 那么只要该列表是可变的 , 而且可能要被多个线程拜望, 您就必需要么在对其进行迭代

23、操作期间, 要么在迭代前进行的克隆操作期间, 锁定整个列表 , 这两种做法的开销都很大 .当对列表执行会引起列表发生变化的操作时, CopyOnWriteArrayList并不是为列表创建一个全新的副本 , 它的迭代器确定能够返回在迭代器被创建时列表的状态, 而不会抛出ConcurrentModificationException. 在对列表进行迭代之前不必克隆列表或者在迭代期间锁定列表, 由于迭代器所看到的列表的副本是不变的. 换句话说 , CopyOnWriteArrayList含有对一个不行变数组的一个可变的引用 , 因此, 只要保留好那个引用, 您就可以获得不行变的线程安全性的好处,

24、而且不用锁定列表 .终止语同步的集合类 Hashtable和 Vector, 以及同步的包装器类Collections.synchronizedMap和Collections.synchronizedList, 为 Map 和 List供应了基本的有条件的线程安全的实现. 然而, 某些因素使得它们并不适用于具有高度并发性的应用程序中 它们的集合范畴的单锁特性对于可伸缩性来说是一个障碍 ,而且, 许多时候仍必需在一段较长的时间内锁定一个集合, 以防止显现ConcurrentModificationExceptions 反常. ConcurrentHashMap和 CopyOnWriteArray

25、List实现供应了更高的并发性 ,同时仍保住了线程安全性, 只不过在对其调用者的承诺上打了点折扣. ConcurrentHashMap和 CopyOnWriteArrayList并不是在您使用 HashMap 或 ArrayList的任何的方都确定有用 ,但是它们是设计用来优化某些特定的公用解决方案的. 许多并发应用程序将从对它们的使用中获得好处 .Java 理论与实践 : 并发集合类可编辑资料 - - - 欢迎下载精品名师归纳总结ConcurrentHashMap和 CopyOnWriteArrayList供应线程安全性和已改进的可伸缩性级别: 初级Brian Goetz brian, 首席

26、顾问 , Quiotix Corp 2003年 9 月 28 日DougLea的 util.concurrent包除了包含许多其他有用的并发构造块之外, 仍包含了一些主要集合类型List和 Map 的高性能的、线程安全的实现. 在本月的 Java 理论与实践中,BrianGoetz向您呈现了用ConcurrentHashMap替换 Hashtable或 synchronizedMap, 将有多少并发程序获益 . 您可以在本文的 论坛中与作者以及其他读者共享您的想法(您也可以点击文章顶部或者底部的争辩进入论坛) .在 Java 类库中显现的第一个关联的集合类是Hashtable, 它是 JDK

27、1.0的一部分 . Hashtable供应了一种易于使用的、线程安全的、关联的map功能, 这当然也是便利的 . 然而, 线程安全性是凭代价换来的 Hashtable的全部方法都是同步的 . 此时, 无竞争的同步会导致可观的性能代价. Hashtable的后继者HashMap 是作为 JDK1.2中的集合框架的一部分显现的,它通过供应一个不同步的基类和一个同步的包装器 Collections.synchronizedMap, 解决了线程安全性问题 . 通过将基本的功能从线程安全性中分别开来, Collections.synchronizedMap答应需要同步的用户可以拥有同步, 而不需要同步的

28、用户就不必为同步付出代价 .Hashtable和 synchronizedMap所实行的获得同步的简洁方法(同步Hashtable中或者同步的Map 包装器对象中的每个方法)有两个主要的不足. 第一, 这种方法对于可伸缩性是一种障碍, 由于一次只能有一个线程可以拜望 hash 表. 同时, 这样仍不足以供应真正的线程安全性, 许多公用的混合操作仍然需要额外的同步. 虽然诸如 get和 put之类的简洁操作可以在不需要额外同步的情形下安全的完成,但仍是有一些公用的操作序列 , 例如迭代或者 put-if-absent(空就放入) , 需要外部的同步 , 以防止数据争用 .有条件的线程安全性同步的

29、集合包装器 synchronizedMap和 synchronizedList, 有时也被称作有条件的线程安全 全部单个的操作都是线程安全的,但是多个操作组成的操作序列却可能导致数据争用, 由于在操作序列中把握流取决于前面操作的结果 .清单 1 中第一片段呈现了公用的put-if-absent语句块 假如一个条目不在Map 中, 那么添加这个条目 . 不幸的是 , 在 containsKey方法返回到 put方法被调用这段时间内 , 可能会有另一个线程也插入一个带有相同键的值. 假如您想确保只有一次插入, 您需要用一个对 Map m 进行同步的同步块将这一对语句包装起来.清单 1 中其他的例子

30、与迭代有关. 在第一个例子中 , List.size的结果在循环的执行期间可能会变得无效,由于另一个线程可以从这个列表中删除条目. 假如时机不得当 , 在刚好进入循环的最终一次迭代之后有一个条目被另一个线程删除了 , 就 List.get将返回 null, 而 doSomething就很可能会抛出一个NullPointerException反常. 那么, 实行什么措施才能防止这种情形了?假如当您正在迭代一个List时另一个线程也可能正在拜望这个List, 那么在进行迭代时您必需使用一个synchronized块将这个 List 包装起来 , 在 List1 上同步 , 从而锁住整个 List.

31、 这样做虽然解决了数据争用问题,但是在并发性方面付出 了更多的代价 , 由于在迭代期间锁住整个List会堵塞其他线程 , 使它们在很长一段时间内不能拜望这个列表.集合框架引入了迭代器 ,用于遍历一个列表或者其他集合, 从而优化了对一个集合中的元素进行迭代的过程.然而, 在 java.util集合类中实现的迭代器极易崩溃, 也就是说 , 假如在一个线程正在通过一个Iterator遍历集合时 , 另一个线程也来修改这个集合, 那么接下来的Iterator.hasNext或 Iterator.next调可编辑资料 - - - 欢迎下载精品名师归纳总结用将抛出 ConcurrentModificati

32、onException反常. 就拿刚才这个例子来讲 , 假如想要防止显现ConcurrentModificationException反常, 那么当您正在进行迭代时, 您必需使用一个在List l上同步的 synchronized块将该 List包装起来 , 从而锁住整个 List.(或者 , 您也可以调用 List.toArray, 在不同步的情形下对数组进行迭代,但是假如列表比较大的话这样做代价很高).Map m = Collections.synchronizedMapnew HashMap List l = Collections.synchronizedListnew ArrayLi

33、st/ put-if-absent idiom - contains a race condition/ may require external synchronization if .map.containsKeykey。map.putkey, value。/ ad-hoc iteration - contains race conditions/ may require external synchronizationfor int i=0。 ilist.size。 i+ doSomethinglist.geti。/ normal iteration - can throw Concur

34、rentModificationException/ may require external synchronizationfor Iterator i=list.iterator doSomethingi.next。 i.hasNext。 。清单 1.同步的 map中的公用竞争条件信任的错觉synchronizedList和 synchronizedMap供应的有条件的线程安全性也带来了一个隐患开发者会假设, 由于这些集合都是同步的 , 所以它们都是线程安全的, 这样一来他们对于正确的同步混合操作这件事就会疏忽. 其结果是尽管表面上这些程序在负载较轻的时候能够正常工作, 但是一旦负载较重

35、, 它们就会开头抛出NullPointerException或 ConcurrentModificationException.可伸缩性问题可伸缩性指的是一个应用程序在工作负载和可用处理资源增加时其吞吐量的表现情形 . 一个可伸缩的程序能够通过使用更多的处理器、内存或者 I/O 带宽来相应的处理更大的工作负载 . 锁住某个共享的资源以获得独占式的拜望这种做法会形成可伸缩性瓶颈 它使其他线程不能拜望那个资源 ,即使有闲暇的处理器可以调用那些线程也无济于事 . 为了取得可伸缩性 , 我们必需排除或者削减我们对独占式资源锁的依靠 .同步的集合包装器以及早期的Hashtable和 Vector类带来的

36、更大的问题是 , 它们在单个的锁上进行同步. 这意味着一次只有一个线程可以拜望集合,假如有一个线程正在读一个Map, 那么全部其他想要读或者写这个 Map 的线程就必需等待 . 最常见的 Map 操作, get和 put,可能比表面上要进行更多的处理 当遍历一个 hash表的 bucket以期找到某一特定的key 时, get必需对大量的候选 bucket调用Object.equals.假如 key 类所使用的 hashCode函数不能将 value均匀的分布在整个 hash 表范畴内, 或者存在大量的 hash 冲突, 那么某些 bucket链就会比其他的链长许多 , 而遍历一个长的 has

37、h 链以及对该 hash 链上确定百分比的元素调用equals是一件很慢的事情 . 在上述条件下 , 调用 get和 put 的代价高的问题不仅仅是指拜望过程的缓慢, 而且, 当有线程正在遍历那个hash 链时, 全部其他线程都被锁在外面 , 不能拜望这个 Map.可编辑资料 - - - 欢迎下载精品名师归纳总结(哈希表依据一个叫做hash的数字关键字( key )将对象储备在 bucket中.hash value是从对象中的值运算得来的一个数字 .每个不同的 hash value都会创建一个新的 bucket.要查找一个对象 , 您只需要运算这个对象的 hash value并搜寻相应的 bu

38、cket就行了 . 通过快速的找到相应的bucket,就可以削减您需要搜寻的对象数量了. 译者注)get执行起来可能会占用大量的时间, 而在某些情形下 , 前面已经作了争辩的有条件的线程安全性问题会让这个问题变得仍要糟糕得多. 清单 1 中演示的争用条件常常使得对单个集合的锁在单个操作执行完毕之后仍必需连续保持一段较长的时间. 假如您要在整个迭代期间都保持对集合的锁, 那么其他的线程就会在锁外停留很长的一段时间 ,等待解锁 .实例:一个简洁的 cacheMap 在服务器应用中最常见的应用之一就是实现一个cache.服务器应用可能需要缓存文件内容、生成的 页面、数据库查询的结果、与经过解读的XM

39、L 文件相关的 DOM 树, 以及许多其他类型的数据 .cache的主要用途是重用前一次处理得出的结果以削减服务时间和增加吞吐量.cache工作负载的一个典型的特点 就是检索大大多于更新 ,因此(理想情形下) cache能够供应特殊好的get性能. 不过, 使用会阻碍性能的 cache仍不如完全不用 cache.假如使用 synchronizedMap来实现一个 cache, 那么您就在您的应用程序中引入了一个潜在的可伸缩性瓶颈. 由于一次只有一个线程可以拜望Map, 这些线程包括那些要从Map 中取出一个值的线程以及那些要将一个新的 key, value对插入到该 map 中的线程 .减小锁

40、粒度提高 HashMap 的并发性同时仍供应线程安全性的一种方法是废止对整个表使用一个锁的方式, 而接受对hash 表的每个 bucket都使用一个锁的方式(或者, 更常见的是 , 使用一个锁池 , 每个锁负责爱惜几个bucket). 这意味着多个线程可以同时的拜望一个Map 的不同部分 , 而不必争用单个的集合范畴的锁. 这种方法能够直接提高插入、检索以及移除操作的可伸缩性.不幸的是 , 这种并发性是以确定的代价换来的这使得对整个集合进行操作的一些方法(例如size或 isEmpty)的实现更加困难 , 由于这些方法要求一次获得许多的锁, 并且仍存在返回不正确的结果的风险. 然而, 对于某些

41、情形 , 例照实现 cache, 这样做是一个很好的折衷 由于检索和插入操作比较频繁,而 size和 isEmpty操作就少得多 .ConcurrentHashMaputil.concurrent包中的 ConcurrentHashMap类(也将显现在 JDK 1.5中的 java.util.concurrent包中)是对Map 的线程安全的实现 , 比起 synchronizedMap来, 它供应了好得多的并发性 . 多个读操作几乎总可以并发的执行 ,同时进行的读和写操作通常也能并发的执行, 而同时进行的写操作仍然可以不时的并发进行(相关的类也供应了类似的多个读线程的并发性, 但是, 只答应

42、有一个活动的写线程) .ConcurrentHashMap被设计用来优化检索操作。实际上, 成功的 get操作完成之后通常根本不会有锁着的资源 . 要在不使用锁的情形下取得线程安全性需要确定的技巧性, 并且需要对 Java 内存模型(Java Memory Model)的细节有深化的懂得 . ConcurrentHashMap实现, 加上 util.concurrent包的其他部分 , 已经被争辩正确性和线程安全性的并发专家所正视. 在下个月的文章中 , 我们将看看ConcurrentHashMap的实现的细节 .ConcurrentHashMap通过略微的放松它对调用者的承诺而获得了更高的并

43、发性. 检索操作将可以返回由最近完成的插入操作所插入的值, 也可以返回在步调上是并发的插入操作所添加的值(但是决不会返回一个没有意义的结果) .由 ConcurrentHashMap.iterator返回的 Iterators将每次最多返回一个元素 , 并且决不会抛出 ConcurrentModificationException反常, 但是可能会也可能不会反映在该迭代器被构建之后发生的插入操作或者移除操作. 在对集合进行迭代时, 不需要表范畴的锁就能供应线程安全性. 在任何不依靠于锁整个表来防止更新的应用程序中,可以使用 ConcurrentHashMap来替代 synchronizedMa

44、p或Hashtable.可编辑资料 - - - 欢迎下载精品名师归纳总结上述改进使得 ConcurrentHashMap能够供应比 Hashtable高得多的可伸缩性 , 而且, 对于许多类型的公用案例(比如共享的 cache )来说 , 仍不用缺失其效率 .好了多少?表 1 对 Hashtable和 ConcurrentHashMap的可伸缩性进行了粗略的比较. 在每次运行过程中 , n 个线程并发的执行一个死循环, 在这个死循环中这些线程从一个Hashtable或者 ConcurrentHashMap中检索随机的 key value,发觉在执行put操作时有 80% 的检索失败率 , 在执行操作时有 1% 的检索成功率 . 测试所在的平台是一个双处理器的Xeon 系统, 操作系统是 Linux. 数据显示了 10,000,000次迭代以毫秒计的运行时间 , 这个数据是在将对ConcurrentHashMap的 操作标准化为一个线程的情形下进行统计的. 您可以看到, 当线程增加到多个时 , ConcurrentHashMap的性能仍然保持上升趋势, 而 Hashtable的性能就随着争用锁的情形的显现而马上降了下来.比起通常情形下的服务器应用, 这次测试中线程的数量看上去有点少. 然而,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁