JAVA并发编程(六)-并发集合

Scroll Down

JAVA并发编程(六)-并发集合

JDK1.5版本之后引入了一些新的线程安全的集合对象,称为并发集合.

非线程安全对象并发集合类共同接口遍历实现方式
ArrayListCopyOnWriteArrayListList快照
HashSetCopyOnWriteArraySetSet快照
LinkedListConcurrentLinkedQueueQueue准实时
HashMapConcurrentHashMapMap准实时
TreeMapConcurrentSkipListMapSortedMap准实时
TreeSetConcurrentSkipListSetSortedSet准实时

并发集合实现线程安全的遍历通常有两种方式,一种是对待遍历对象的快照进行遍历.另一种是对待遍历对象进行准实时的遍历.

快照遍历:

  • 快照是在Iterator实例被创建的那一刻待遍历对象内部结构的一个只读副本,它所反应的是待遍历集合某一时刻的状态,由于对同一个并发集合进行遍历的线程都会得到相应的快照,所以快照相当于每个线程的特有对象,是可以实现线程安全的,这种返回的Iterator无法进行remove操作.
  • 优点:遍历与更新操作之间互不影响(操作的不同对象)
  • 缺点:如果集合数据量较大,创建实例的副本消耗较大

准实时遍历:

  • 准实时遍历操作不是针对待遍历对象的副本进行的,但又不借助锁来保障线程安全,从而使得遍历操作可以与更新操作并发进行,遍历过程中其他线程对遍历对象的内部结构的更新可能会(也可能不会)反映出来.这种遍历方式返回的Iterator是支持remove方法的,但是Iterator是被设计来一次只能被一个线程使用的,因此如果有多个线程要进行遍历操作,那么这些线程是不适宜共享同一个Iterator实例.

并发集合内部在保障其线程安全的时候通常不借助锁,而是使用CAS操作,或者对锁进行了优化,例如使用粒度较小的锁.所以并发集合的可伸缩性一般要比相应的同步集合高,使用并发集合的程序相对于相应同步集合的程序而言,并发线程数的增加带来的程序吞吐率提升更加显著,而使用同步集合的程序随着并发线程数据量的上升,这些同步集合内部锁使用的锁的争用所导致的上下文切换开销越来越大.

ConcurrentLinkedQueue

ConcurrentLinkedQueue 是Queue接口的一个线程安全实现类,它相当于LinkedList的线程安全版本.ConcurrentLinkedQueue内部访问其共享状态变量的时候并不借助锁,而是使用CAS操作来保障线程安全的,因此ConcurrentLinkedQueue是非阻塞的,其使用不会导致当前线程被暂停.也就避免了上下文切换的开销.ConcurrentLinkedQueue 适合于更新操作和遍历操作并发的场景.

ConcurrentHashMap

ConcurrentHashMap是Map接口的一个线程安全实现类,它相当于HashMap(也是一个Map接口的实现类)的线程安全版,ConcurrentHashMap内部使用了粒度极小的锁来保障线程安全.ConcurrentHashMap的读取操作基本不会导致锁的使用,并且默认情况下ConcurrentHashMap支持16个线程并发更新线程.这些数据可以在不导致锁的争用情况下进行并发更新,因此ConcurrentHashMap可以支持比较高的并发性,并且其锁的开销比较小.ConcurrentHashMap中有个构造器支持concurrencyLevel的值进行调整,值越大开销越大,值越小可能导致锁的争用增高,所以concurrencyLevel的值需要实际的情况来权衡

CopyOnWriteArrayList

CopyOnWriteArrayList是List接口的一个线程安全实现类,相当于ArrayList的线程安全版,CopyOnWriteArrayList内部会维护一个实例变量array用于引用一个数组,该数组用于存储列表的各个元素.CopyOnWriteArrayList的更新操作都是创建一个新的数组newArray,并把老的数组的内容复制到newArray,然后对newArray进行更新并将array指向newArray,因此所有对CopyOnWriteArrayList的更新操作都会导致对象的复制,CopyOnWriteArrayList适用于遍历操作远比更新操作更为频繁或者不希望在遍历的时候加锁的场景,其他的场景下,需要考虑使用CollectionUtils.synchronizedList(new ArrayList());

CopyOnWriteArraySet

CopyOnWriteArraySet 是Set接口的一个线程安全实现类,相当于HashSet的线程安全版,CopyOnWriteArraySet内部实现使用了一个CopyOnWriteArrayList实例,因此CopyOnWriteArraySet 也是适用于遍历操作远比更新操作更为频繁或者不希望在遍历的时候加锁的场景