并发编程 — 并发数据结构

本文深入探讨了并发编程中常见的线程安全问题,并介绍了如何将传统数据结构转换为线程安全的版本。文中详细分析了Vector与CopyOnWriteArrayList、ConcurrentHashMap及不同类型的并发队列(如ConcurrentLinkedQueue和BlockingQueue)的特点与适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=medium]
并发编程系列文章:
初解线程池:[url]http://ray-yui.iteye.com/blog/2072463[/url]
详解线程池:[url]http://ray-yui.iteye.com/blog/2075311[/url]
并发数据类型:[url]http://ray-yui.iteye.com/blog/2080454[/url]
并发数据结构:[url]http://ray-yui.iteye.com/blog/2084202[/url]
volatile:[url]http://ray-yui.iteye.com/blog/2231474[/url]
判断线程安全:[url]http://ray-yui.iteye.com/blog/2232931[/url]
实现线程安全:[url]http://ray-yui.iteye.com/blog/2234688[/url]
[/size]
[size=medium]
[b][color=red]由于并行程序与串行程序的不同特点,适用于串行程序当中的常用数据结构在并发环境中会引发线程安全问题[/color][/b],例如[b]ArrayList,HashSet,HashMap[/b]等,这是因为这些数据结构不是线程安全的,所以编写并行程序时需要将原串行数据结构转换为线程安全或使用对并行程序效率更高的并行数据结构
[/size]
[size=medium]
[b][color=red]使传统集合更改为线程安全集合[/color][/b]
[/size]

public class TestMain {
@Test
public void testTraditionCollections() throws Exception {

// Collections中提供多种方法将集合变成线程安全

// 转换ArrayList
Collections.synchronizedList(new ArrayList<Object>());

// 转换HashMap
Collections.synchronizedMap(new HashMap<Object, Object>());

// 转换HashSet
Collections.synchronizedSet(new HashSet<Object>());
}
}

[size=medium]
[color=red]并发[b]List[/b][/color]
[b]Vector[/b]和[b]CopyOnWriteArrayList[/b]是两个线程安全的[b]List[/b]实现,而[b]Vector[/b]和[b]CopyOnWriteArrayList[/b]的内部实现又有所不同,[b]Vector[/b]使用锁机制实现线程安全,在多线程世界中锁是并发的最大敌人,太多的锁竞争会消耗系统资源和降低并发,而[b]CopyOnWriteArrayList[/b]实现并不使用锁,而是使用了对象的不变性,在对象读取时不需要加锁,而是在试图改变对象时,先获取对象的一个copy,对copy进行修改后将副本回写,减少了锁竞争提高了并发时的读取性能,但某程度上牺牲了写的性能,[color=red]当写操作频繁时请选择[b]Vector[/b],当高并发读取时,应该选择[b]CopyOnWriteArrayList[/b][/color]
[/size]

[size=medium]
[color=red]并发[b]Set[/b][/color]
对比上述并发[b]List[/b],[b]Set[/b]当中亦存在[b]CopyOnWriteArraySet[/b],对应并发[b]List[/b]当中的[b]CopyOnWriteArrayList[/b],而[b]Vector[/b]对应使用[b]Collections.synchronizedSet[/b]后的[b]Set[/b]
[/size]

[size=medium]
[color=red]并发[b]Map[/b][/color]
在并发环境中使用[b]Collections.synchronizedMap[/b]可以获取线程安全的[b]Map[/b],或HashTable,但JDK提供了另一种并发[b]ConcurrentHashMap[/b],[b]ConcurrentHashMap[/b]的读写速度比同步[b]Map[/b]速度更快,[b]ConcurrentHashMap[/b]如此高效得益于它的get操作是无锁的,而put操作锁的粒度比同步的[b]Map[/b]小,[color=red]在高并发环境中务必优先选择[b]ConcurrentHashMap[/b][/color]
[/size]

[size=medium]
[color=red]并发[b]Queue[/b][/color]
在并发[b]Queue[/b]中提供了两套具有代表性的实现,分别是高性能的[b]ConcurrentLinkedQueue[/b]和[b]BlockingQueue[/b],[color=red][b]ConcurrentLinkedQueue[/b]适用于高并发的读写,它通过无锁的方式实现高性能,[b]BlockingQueue[/b]的主要功能并不是体现在提升并发时队列的性能,而在于简化多线程之间的数据共享[/color],阻塞队列在生产者-消费者模式中得到了完美的体现,[b]BlockingQueue[/b]提供了3种存取方式,请读者参考JDK文档

PS:[b]BlockingQueue[/b]有[b]ArrayBlockingQueue[/b]和[b]LinkedBlockingQueue[/b]两个实现类,相信读者已熟悉[b]Array[/b]和[b]Linked[/b]的区别,此乃经典面试题,笔者在此不再叙述
[/size]

[size=medium]
[color=red]并发[b]Deque[/b][/color]
[b]Deque[/b]是基于链接点的阻塞栓双端队列,[color=red][b]Deque[/b]允许在队列的头部或者尾部进行读写[/color],[b]LinkedList[/b]也实现了[b]Deque[/b]接口,[b]Deque[/b]和[b]Queue[/b]一样提供了3种元素的存取方式,甚至提供了指读取不删除的操作方式,详情请读者查看JDK帮助文档,但[b]LinkedBlockingDeque[/b]并没有进行读写锁分离,因此在效率方面要低于[b]LinkedBlockingQueue[/b]更远低于[b]ConcurrentLinkedQueue[/b]
[/size]
[size=medium]
总结:
软件中数据结构博大精深,但万变不离经典,除了要熟练使用传统串行数据结构外,还需要对并发的数据结构有所认识和了解,特别在开发并行程序时需要格外注意,否则将出现非常难以重现的错误,在并发数据结构中还有Apache下的Amino框架,Amino框架提供更快速实现CAS算法的数据结构,详情请留意笔者后续文章
[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值