最全java多线程总结3——了解阻塞队列和线程安全集合不 (2)

使用 AtomicLong 或者 LongAdder 作为映射的值,这两个的操作方法是原子性的,因此可以安全的修改值。 3.使用 compute 类似方法完成更新。比如下面的:

# 如果key不再map中,v的值为null map.compute(key,(k,v)->v==null?1:v+1); # 如果不存在key map.computeIfAbsent(key,key->new LongAdder()) # 如果存在key map.computeIfPresent(key,key->key+1) # 和compute方法类似,不过不处理键 map.merge(key,value,(existingValue,newValue)->existingValue+newValue+1) 批操作

  java8 引入的,即使有其他线程在处理映射,批操作也能安全的执行。批操作会遍历映射,处理便利过程中找到的元素,且无需冻结当前映射的快照。显然通过批操作获取的结果不是完全精确的,因为遍历过程中,元素可能会被改变。

  有以下三种不同的操作:

搜索(search),遍历结果直到返回一个非 null 的结果

归约(reduce),组合所有键或值,需提供累加函数

forEach,遍历所有的键值对
每个操作都有 4 个版本:

operationKeys:处理键

operationValues:处理值

operation:处理键值

operationEntries:处理需要 map.Entry 对象

并发集合

  线程安全的 set 集合只有以下一种:

ConcurrentSkipListSet:有序 set
如果我们想要一个 hash 结构的,线程安全的 set,有以下几种办法.

通过 ConcurrentHashMap.<Key>newKeySet()生成一个 Set,比如:

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

这其实只是 ConcurrentHashMap<Key,Boolean>的一个包装器,所有的值都为 true

通过现有映射对象的 keySet 方法,生成这个映射的键集。如果删除这个集的某个元素,映射上对于元素也会被删除。但是不能添加元素,因为没有相应的值。java8 新增了一个 keySet 方法,可以设置一个默认值,这样就能为向集合中增加元素。

数组

  在 Concurrent 包中只有一个CopyOnWriteArrayList数组。该数组所有的修改都会对底层数组进行复制,也就是每插入一个元素都会将原来的数组复制一份并加入新的元素。

  当构建一个迭代器时,迭代器指向的是当前数组的引用,如果后来数组被修改了,迭代器指向的任然是旧的数组。

任何集合类都可以通过使用同步包装器变成线程安全的,如下:

//线程安全的列表 List<String> list1 = Collections.synchronizedList(new ArrayList<>()); //线程安全的map Map<String,String> map1 = Collections.synchronizedMap(new HashMap<>()); //线程安全的set Set<String> set1 = Collections.synchronizedSet(new HashSet<>()); 并行数组算法

  在 java 8 中,Arrays 类提供了大量的并行化操作。

Arrays.parallelSort

  对一个基本数据类型或对象的数组进行排序

Arrays.paralletSetAll

  用一个函数计算得到的值填充一个数组。这个函数接收元素索引,然后计算值。例如:

# 将所有值加上对于的序号 Arrays.parallelSetAll(arr,i->i+ arr[i]);

parallelPrefix

  用对应一个给定结合操作的前缀的累加结果替换各个数组元素。看文字描述不太容易看懂,这里用一个例子说明:

int[] arr = {1,2,3,4} Arrays.parallelPrefix(arr,(x,y)->x*y); // arr变成:[1,1*2,1*2*3,1*2*3*4]

本文原创发布与::https://www.tapme.top/blog/detail/2019-04-10

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwyxg.html