并发容器的实现
Java中常用的几个并发容器
容器 | 实现 | 使用场景 |
CopyOnWriteArrayList | 内部是一个数组,这个数组是以原子方式被整体更新的。 写:每次修改操作,都会新建一个数组,复制原数组的内容到新数组,在新数组上进行需要的修改,然后以原子方式设置内部的数组引用,这就是写时复制。多个线程不能同时写,每个写操作都需要先获取锁。CopyOnWriteArrayList内部使用ReentrantLock。 读:先拿到当前引用的数组,然后直接访问该数组。在读的过程中,可能内部的数组引用已经被修改了,但不会影响读操作,它依旧访问原数组内容。读不需要锁,可以并行,读和写也可以并行。 | CopyOnWriteArrayList不适用于数组很大且修改频繁的场景。它是以优化读操作为目标的,读不需要同步,性能很高,但在优化读的同时牺牲了写的性能。 对于绝大部分访问都是读,且有大量并发线程要求读,只有个别线程进行写,且只是偶尔写的场合,写时复制就是一种很好的解决方案。 |
CopyOnWriteArraySet | CopyOnWriteArraySet内部是通过CopyOnWriteArrayList实现的。 其成员声明为: | 性能比较低,不适用于元素个数特别多的集合。如果元素个数比较多,可以考虑ConcurrentHashMap或ConcurrentSkipListSet这两个类。 |
ConcurrentHashMap | 特性
实现
迭代器
弱一致性
| 元素多、较多写线程,对性能要求较高的场景。 Java中没有并发版的HashSet,但可以通过Collections.newSetFromMap方法基于ConcurrentHashMap构建一个。 |
ConcurrentSkipListMap | ConcurrentSkipListMap是基于SkipList实现的。并发版本为什么采用跳表而不是树呢?因为跳表更易于实现高效并发算法。 特性
注意: ConcurrentSkipListMap的size方法与大多数容器实现不同,这个方法不是常量操作,它需要遍历所有元素,复杂度为O(N),而且遍历结束后,元素个数可能已经变了。一般而言,在并发应用中,这个方法用处不大。 | ConcurrentSkipListMap和ConcurrentSkipListSet基于跳表实现,有序,无锁非阻塞,完全并行,主要操作复杂度为O(log(N))。 |
ConcurrentSkipListSet | TreeSet是基于TreeMap实现的,与此类似,ConcurrentSkipListSet也是基于ConcurrentSkipListMap实现的。 |
知其然知其所以然,只有掌握了底层原理,借助第一性原理,才可以在日常开发和项目中运用自如,潇洒走江湖。 专为27届毕业生准备,托起您的就业梦。 该专辑会不定时更新,建议27届同学订阅,入职后扎实的基本功可以帮您争取更好的机会和项目。
查看12道真题和解析