|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
你说是sun公司对她研究的透还是微软?针对自己工具开发的.net网页编程性能上肯定会站上风的。
ConcurrentHashMap是DougLea的util.concurrent包的一部分,它供应比Hashtable大概synchronizedMap更高水平的并发性。并且,关于年夜多半成功的get()操纵它会想法制止完整锁定,其了局就是使得并发使用程序有着非常好的吞吐量。这个月,BrianGoetz细心剖析了ConcurrentHashMap的代码,并切磋DougLea是怎样在不丧失线程平安的情形下获得这么骄人成就的。
在7月份的那期Java实际与理论(“Concurrentcollectionsclasses”)中,我们复杂地回忆了可伸缩性的瓶颈,并会商了怎样用共享数据布局的办法获得更高的并发性和吞吐量。偶然候进修的最好办法是剖析专家的功效,以是这个月我们将剖析DougLea的util.concurrent包中的ConcurrentHashMap的完成。JSR133将指定ConcurrentHashMap的一个版本,该版本针对Java内存模子(JMM)作了优化,它将包括在JDK1.5的java.util.concurrent包中。util.concurrent中的版本在老的和新的内存模子中都已经由过程线程平安考核。
针对吞吐量举行优化
ConcurrentHashMap利用了几个技能来取得高水平的并发和制止锁定,包括为分歧的hashbucket(桶)利用多个写锁和利用JMM的不断定性来最小化锁被坚持的工夫DD大概基本制止猎取锁。关于年夜多半一样平常用法来讲它是经由优化的,这些用法常常会检索一个极可能在map中已存在的值。现实上,多半乐成的get()操纵基本不必要任何锁定就可以运转。(告诫:不要本人试图如许做!想比JMM伶俐不像看上往的那末简单。util.concurrent类是由并发专家编写的,而且在JMM平安性方面经由了严厉的偕行评审。)
多个写锁
我们能够回忆一下,Hashtable(大概替换计划Collections.synchronizedMap)的可伸缩性的次要停滞是它利用了一个map局限(map-wide)的锁,为了包管拔出、删除大概检索操纵的完全性必需坚持这样一个锁,并且偶然候乃至还要为了包管迭代遍历操纵的完全性坚持如许一个锁。如许一来,只需锁被坚持,就从基本上制止了其他线程会见Map,即便处置器有余暇也不克不及会见,如许年夜年夜地限定了并发性。
ConcurrentHashMap摒弃了单一的map局限的锁,取而代之的是由32个锁构成的汇合,个中每一个锁卖力回护hashbucket的一个子集。锁次要由变更性操作(put()和remove())利用。具有32个自力的锁意味着最多能够有32个线程能够同时修正map。这其实不必定是说在并发地对map举行写操纵的线程数少于32时,别的的写操纵不会被堵塞DD32关于写线程来讲是实际上的并发限定数量,可是实践上大概达不到这个值。可是,32仍然比1要好很多,并且关于运转于今朝这一代的盘算机体系上的年夜多半使用程序来讲已充足了。 
map局限的操纵
有32个自力的锁,个中每一个锁回护hashbucket的一个子集,如许必要独占会见map的操纵就必需取得一切32个锁。一些map局限的操纵,好比说size()和isEmpty(),大概可以不必一次锁全部map(经由过程得当地限制这些操作的语义),可是有些操纵,好比map重排(扩展hashbucket的数目,跟着map的增加从头散布元素),则必需包管独有会见。Java言语不供应用于猎取可变巨细的锁汇合的烦琐办法。必需这么做的情形很少见,一旦碰着这类情形,可以用递回办法来完成。
JMM概述
在进进put()、get()和remove()的完成之前,让我们先复杂地看一下JMM。JMM掌管着一个线程对内存的举措(读和写)影响其他线程对内存的举措的体例。因为利用处置器存放器和预处置cache来进步内存会见速率带来的性能提拔,Java言语标准(JLS)同意一些内存操纵其实不关于一切其他线程当即可见。有两种言语机制可用于包管跨线程内存操纵的分歧性DDsynchronized和volatile。
依照JLS的说法,“在没有显式同步的情形下,一个完成能够自在地更新主存,更新时所接纳的按次多是出人意表的。”其意义是说,假如没有同步的话,在一个给定线程中某种按次的写操纵关于别的一个分歧的线程来讲大概出现出分歧的按次,而且对内存变量的更新从一个线程传布到别的一个线程的工夫是不成展望的。
固然利用同步最多见的缘故原由是包管对代码关头部分的原子会见,但实践上同步供应三个自力的功效DD原子性、可见性温柔序性。原子性十分复杂DD同步实行一个可重进的(reentrant)互斥,避免多于一个的线程同时实行由一个给定的监督器回护的代码块。不幸的是,多半文章都只存眷原子性方面,而疏忽了其他方面。可是同步在JMM中也饰演着很主要的脚色,会引发JVM在取得和释放监督器的时分实行内存壁垒(memorybarrier)。
一个线程在取得一个监督器以后,它实行一个读屏蔽(readbarrier)DD使得缓存在线程部分内存(好比说处置器缓存大概处置器存放器)中的一切变量都生效,如许就会招致处置重视新从主存中读取同步代码块利用的变量。与此类似,在开释监督器时,线程会实行一个写屏蔽(writebarrier)DD将一切修悔改的变量写回主存。互斥独有和内存壁垒分离利用意味着只需您在程序计划的时分遵守准确的同步法例(也就是说,每当写一个前面大概被其他线程会见的变量,大概读取一个大概最初被另外一个线程修正的变量时,都要利用同步),每一个线程城市失掉它所利用的共享变量的准确的值。
假如在会见共享变量的时分没有同步的话,就会产生一些奇异的事变。一些变更大概会经由过程线程当即反应出来,而其他的则必要一些工夫(这由联系关系缓存的实质而至)。了局,假如没有同步您就不克不及包管内存内容一定分歧(相干的变量互相间大概会纷歧致),大概不克不及失掉以后的内存内容(一些值多是过期的)。制止这类伤害情形的经常使用办法(也是保举利用的办法)固然是准确地利用同步。但是在有些情形下,好比说在像ConcurrentHashMap之类的一些利用十分广泛的库类中,在开辟历程傍边还必要一些分外的专业妙技和勉力(大概比一样平常的开辟要多出良多倍)来取得较高的功能。
<p>
在性能方面,在windows平台下,.net网页编程可能是占强项,要是把.net网页编程放在sun开发的操作系统上去运行呢?根本就运行不了,.net网页编程对其它操作系统的支持也很弱,性能也可能比不上java。 |
|