美文网首页
同步----线程安全的集合

同步----线程安全的集合

作者: 爱做梦的严重精神病患者 | 来源:发表于2019-03-19 10:40 被阅读0次

  除了阻塞队列(BlockingQueue),java.util.concurrent提供了映射、有序集和队列的高效实现:ConcurrentHashMapConcurrentSkipListMapConcurrentSkipListSetConcurrentLinkedQueue。这些集合使用复杂的算法,通过允许并发地访问数据结构的不同部分来使竞争极小化。
  与大多数集合不同,size方法不必在常量时间内操作。确定这样的集合当前的大小通常需要遍历

1.对并发散列映射的批操作

  Java SE 8为并发散列映射提供了批操作,即使有其他线程在处理映射,这些操作也能安全地执行。
  有3种不同的操作

  • 搜索
  • 归约
  • forEach
      每个操作都有4个版本
  • operationKeys:处理键
  • operationValues: 处理值
  • operation:处理键和值
  • operationEntries:处理Map.Entry对象
      以search方法为例,有以下版本:
U searchKeys(long threshold, BiFunction<? super K, ? extends U> f)
U searchValues(long threshold, BiFunction<? super K, ? extends U> f)
U search(long threshold, BiFunction<? super K, ? extends U> f)
U searchEntries(long threshold, BiFunction<<Map.Entry<K, V>>, ? extends U> f)

2.并发集视图

  假如想要的是一个大线程安全的集而不是映射,并没有一个ConcurrentHashSet类静态newKeySet方法生成一个Set<K>,这实际上是ConcurrentHashMap<K, Boolean>的一个包装器。(所有的映射值都为Boolean.TRUE,不过因为只是要把它用作一个集,所以并不关心具体的值。)

Set<String> words = ConcurrentHashMap.<String>newKeySet();

  如果原来有一个映射,keySet方法可以生成这个映射的键集。这个集是可变的,如果删除这个集的元素,这个键(以及相应的值)会从映射中删除。不过,不能向键集增加元素,因为没有相应的值可以增加。
  Java SE 8ConcurrentHashMap增加了第二个keySet方法,包含一个默认值,可以在为集增加元素时使用

Set<String> words = map.keySet(1L);
words.add("Java");
//如果"Java"在words中不存在,现在它会有一个值1。

3.写数组的拷贝

  CopyOnWriteArrayListCopyOnWriteArraySet线程安全的集合,其中所有的修改线程对底层数组进行复制。如果在集合上进行迭代的线程数超过修改线程数,这样的安排是很有用的。
  当构建一个迭代器的时候,它包含一个对当前数组的引用。如果数组后来被修改了,迭代器仍然引用旧数组,但是,集合的数组已经被替换了。因而,旧的迭代器拥有一致的(可能过时的)视图,访问它无须任何同步开销。

4.并行数组算法

  在Java SE 8中,Arrays类提供了大量并行化操作静态Arrays.parallelSort方法可以对一个基本类型值对象数组排序
  parallelSetAll方法会用由一个函数计算得到的值填充一个数组。这个函数接收元素索引,然后计算相应位置上的值。
  最后还有一个parallelPrefix方法,它会用对应一个给定结合操作的前缀累加结果替换各个数组元素。如果有足够多的处理器,这会远远胜过直接的线性计算。

5.同步包装器

  从Java的初始版本开始,VectorHashtable类就提供线程安全的动态数组散列表的实现。现在这些类被弃用了,取而代之的是ArrayListHashMap类。这些不是线程安全的,而集合库中提供了不同的机制。任何集合类都可以通过使用同步包装器(synchronization wrapper)变成线程安全的

List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E> ());
Map<K, V> synchHashMap = Collections.synchronizedMap(new HashMap<K, V> ());
//集合的方法使用锁加以保护,提供了线程安全访问。

  应该确保没有任何线程通过原始的非同步方法访问数据结构。最便利的方法是确保不保存任何指向原始对象的引用,简单地构造一个集合并立即传递给包装器。
  如果在另一个线程可能进行修改时要对集合进行迭代,仍然需要使用“客户端”锁定:

synchronized(synchHashMap) {
    Iterator<K> iter = synchHashMap.keySet().iterator();
    while (iter.hasNext())...;
}

  最好使用java.util.concurrent包中定义的集合,不使用同步包装器中。有一个例外经常被修改的数组列表。在那种情况下,同步的ArryaList可以胜过CopyOnWriteArrayList。

相关文章

网友评论

      本文标题:同步----线程安全的集合

      本文链接:https://www.haomeiwen.com/subject/yzuwmqtx.html