注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一线天色 天宇星辰

天下武功,唯快不破

 
 
 

日志

 
 

Java并发包中常用类小结(一)  

2012-04-24 22:40:17|  分类: 并发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

JDK1.5以后,Java为我们引入了一个并发包,用于解决实际开发中经常用到的并发问题,那我们今天就来简单看一下相关的一些常见类的使用情况。

1ConcurrentHashMap

ConcurrentHashMap其实就是线程安全版本的hashMap。前面我们知道HashMap是以链表的形式存放hash冲突的数据,以数组形式存放HashEntryhash出来不一致的数据。为了保证容器的数据一致性,需要加锁。HashMap的实现方式是,只有putremove的时候会引发数据的不一致,那为了保证数据的一致性,我在putremove的时候进行加锁操作。但是随之而来的是性能问题,因为key-value形式的数据,读写频繁是很正常的,也就意味着我有大量数据做读写操作时会引发长时间的等待。为了解决这个问题,Java并发包问我们提供了新的思路。在每一个HashEnry上加一把锁,对于hash冲突的数据,因为采用链表存储,公用一把锁。这样我在才做不同hash数值的数据时,则是在不同的锁环境下执行,基本上是互不干扰的。在最好情况下,可以保证16个线程同时进行无阻塞的操作(HashMap的默认HashEntry16,亦即默认的数组大小是16)。

ConcurrentHashMap是如何保证数据操作的一致性呢?对于数据元素的大小,ConcurrentHashMap将对应数组(HashEntry的长度)的变量为voliate类型的,也就是任何HashEntry发生变更,所有的地方都会知道数据的大小。对于元素,如何保证我取出的元素的next不发生变更呢?(HashEntry中的数据采用链表存储,当读取数据的时候可能又发生了变更),这一点,ConcurrentHashMap采取了最简单的做法,hash值、keynext取出后都为final类型的,其next等数据永远不会发生变更。

另外ConcurrentHashMap采用的锁结构是将读和写分开的,大大的提升了性能,下面我们来看一下两者之间的性能差。

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 由于数据比较密集,我们分开来看一下

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰
Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰 
Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰
Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 相关数据如下:

分析表

元素个数

10

100

1000

10000

线程数

容器类别

增加

删除

查找

增加

删除

查找

增加

删除

查找

增加

删除

查找

1

HashMap

2805

1743

1520

3004

1726

1579

1995

1846

1528

2032

1787

1501

ConcurrentHashMap

4947

2010

1699

5292

2005

1661

2322

1842

1243

2351

2113

1541

10

HashMap

29814

36539

28076

31180

55178

38156

31217

36756

31785

33314

30497

26488

ConcurrentHashMap

18364

22086

8064

21420

22805

9932

20164

20875

7800

19383

19483

10254

50

HashMap

233674

193918

230404

205577

221995

213651

343005

318603

343153

249921

229954

234555

ConcurrentHashMap

131573

98534

16778

152609

96412

24233

123199

108388

20156

134971

122927

18799

100

HashMap

313442

309336

302591

332389

314167

296360

343005

318603

343153

329171

352704

354593

ConcurrentHashMap

161866

122582

21369

141274

114333

21875

116758

97985

24098

140902

120459

18766

(神马情况 数据看不到了 弄一个图吧)

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 

我们可以看到,在单线程下,ConcurrentHashMap的综合性能略低于HashMap,但是随着线程的增长,ConcurrentHashMap的优势就明显提现出来了,尤其是查找元素的性能。因此并发情况下,ConcurrentHashMap是代替HashMap的一个不错的选择。

2CopyOnWriteArrayList

同样的,CopyOnWriteArrayList是线程安全版本的ArrayList。和ArrayList不同的是,CopyOnWriteArrayList默认是创建了一个大小为0的容器。通过ReentrantLock来保证线程安全。CopyOnWriteArrayList其实每次增加的时候,需要新创建一个比原来容量+1大小的数组,然后拷贝原来的元素到新的数组中,同时将新插入的元素放在最末端。然后切换引用。

针对CopyOnWriteArrayList,因为每次做插入和删除操作,都需要重新开辟空间和复制数组元素,因此对于插入和删除元素,CopyOnWriteArrayList的性能远远不如ArrayList,但是每次读取的时候,CopyOnWriteArrayList在不加锁的情况下直接锁定数据,会快很多(但是可能会引发脏读),对于迭代,CopyOnWriteArrayList会生成一个快照数组,因此当迭代过程中出现变化,快照数据没有变更,因此读到的数据也是不会变化的。在读多写少的环境下,CopyOnWriteArrayList的性能还是不错的。

3CopyOnWriteArraySet

CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的。但是CopyOnWriteArraySet鉴于不能插入重复数据,因此每次add的时候都要遍历数据,性能略低于CopyOnWriteArrayList

4ArrayBlockingQueue

ArrayBlockingQueue是基于数组实现的一个线程安全的队列服务,其相关的功能前面我们已经用到过了,这里就不多提了。

5Atomic类,如AtomicIntegerAtomicBoolean

我们来看以下对应的API文档

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

Java并发包中常用类小结(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 这种原子类是基于

JDKCAS的无阻塞操作,比我们写同步的效率要高多了哦。

对于Atomic类我们在后面的示例中也会很频繁的使用,这里也就不多介绍了。

  评论这张
 
阅读(2830)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017