多线程—并发容器与机制

fail-fast 机制

一种错误检测机制。常见的使用fail-fast方式遍历的容器有HashMap和ArrayList等。当在迭代集合的过程中该集合在结构上发生改变的时候,比如单线程遍历时remove(),多线程一个读取数据一个操作数据,就有可能会发生fail-fast,即抛出ConcurrentModificationException异常。

fail-safe 机制

先复制原有集合内容,在拷贝的集合上进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,不会触发Concurrent Modification Exception。java.util.concurrent包下的容器都是fail-safe机制,可以在多线程下并发使用,并发修改。

同步容器  

在Java中,同步容器主要包括2类:

  • Vector、Stack、HashTable
  • Collections类中提供的静态工厂方法创建的类

缺点:

同步容器效率低,fail-fast机制,对同步容器进行迭代的同时修改它的内容,会报ConcurrentModificationException异常。

阻塞队列与非阻塞队列

阻塞队列:当队列满时,队列会阻塞插入元素的线程,直到队列不满;当队列为空时,队列会阻塞获取元素的线程,直到队列不空。

非阻塞队列:若线程从中获取元素,若没有则直接返回空,不会阻塞当前线程

分段锁

简单来说就是将数据进行分段,每一段锁用于锁容器中的一部分数据,那么当多线程访问容器里的不容数据段的数据时,线程间就不会存在锁竞争,从而可以有效地提高并发访问效率。有些方法需要跨段,比如size(),就需要按照顺序锁定所有的段,完成操作后,再按顺序释放锁。

并发容器

采用fail-safe机制。

非阻塞队列

CopyOnWriteArrayList

  • 读写分离,读操作不加锁,所有线程都不会阻塞。写操作加锁,线程会阻塞。
  • 写线程获取到锁,其他线程包括读线程阻塞
  • 实现方式是写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array。
  • 适用于读远远大于写的时候。

ConcurrentHashMap 
多线程环境下,使用Hashmap进行put操作可能会引起死循环。

  • Hashtable实现同步是利用synchronized关键字进行锁定的,其是针对整张哈希表进行锁定的,即每次锁住整张表让线程独占,在线程安全的背后是巨大的浪费。
  • ConcurrentHashMap采用分段锁,单独锁住每一个桶(segment),ConcurrentHashMap将哈希表分为16个桶(默认值),get(),put(),remove()等常用操作只锁当前需要用到的桶。原来只能一个线程进入,现在却能同时接受16个写线程并发进入。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁。

ConcurrentLinkedQueue

  • 一个基于链接节点的无界线程安全队列。
  • 此队列按照 FIFO(先进先出)原则对元素进行排序,新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。
  • 它的主要api是offer和poll, offer将指定元素插入此队列的尾部 ;poll 获取并移除此队列的头,如果此队列为空,则返回 null。

阻塞队列BlockingQueue

在线程池中有所运用,获取不到任务就一直处于阻塞状态。

ArrayBlockingQueue

  • 基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列。
  • ArrayBlockingQueue内部保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。

LinkedBlockingQueue

  • 基于链表的阻塞队列,同ArrayListBlockingQueue类似,其内部也维持着一个数据缓冲队列(该队列由一个链表构成),当生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回;只有当队列缓冲区达到最大值缓存容量时(LinkedBlockingQueue可以通过构造函数指定该值),才会阻塞生产者队列,直到消费者从队列中消费掉一份数据,生产者线程会被唤醒,反之对于消费者这端的处理也基于同样的原理。
  • 没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE)

PriorityBlockingQueue

支持优先级的无界阻塞队列,默认情况下元素按照自然顺序升序排列,可以自定义类实现compareTo()方法来指定元素的排序规则,或在初始化PriorityBlockingQueue时指定构造参数Comparator来对元素进行排序,但不能保证同优先级元素的顺序;
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章