写点什么

Java—并发容器

作者:武师叔
  • 2022 年 6 月 11 日
  • 本文字数:1547 字

    阅读完需:约 5 分钟

Java—并发容器

并发容器


并发原理

Java 提供的基础容器都是线程不安全的,如果并发条件下多个线程同时对一个容器中的数据进行操作,可能会导致各种意想不到的错误。


因此 Java 又提供了一些并发容器在多线程情况下使用,这些并发容器都位于 java.util.concurrent 包内,使用时需要进行导入。



List 接口

Vector 类(已过时)

【数组序列】和 ArrayList 类类似,实现了 List 接口。内部使用 Object 数组存储。


Vector 类内部所有方法都是同步(synchronized) 的,因此线程安全。但高并发场景下非常容易阻塞,性能很差。

CopyOnWriteArrayList 类

【数组序列】和 ArrayList 类类似,实现了 List 接口。内部使用 Object 数组存储。


CopyOnWriteArrayList 对读取操作不上锁,对写入操作上锁。写入操作通过创建数组的副本来实现,修改的内容写入副本后再替换原来的数据。


不允许同时写,但读操作和写操作不冲突,在多读的场合性能非常好。

ConcurrentLinkedQueue 类

【链表序列】和 LinkedList 类类似,实现了 List 以及 Deque 接口。内部使用双向链表存储。


ConcurrentLinkedQueue 类非阻塞,通过 CAS 算法实现线程安全,尝试更新数据时会对数据进行比对。高并发场景下如果加锁的代价很高,可以达到很好的性能。



BlockingQueue 接口

【阻塞队列】被广泛使用在“生产者-消费者”问题中,其原因是 BlockingQueue 提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。

ArrayBlockingQueue 类

有界队列实现类,底层采用数组来实现。ArrayBlockingQueue 一旦创建,容量不能改变。其并发控制采用可重入锁来控制,不管是插入操作还是读取操作,都需要获取到锁才能进行操作。

LinkedBlockingQueue 类

PriorityBlockingQueue 类


Map 接口

HashTable 类(已过时)

【哈希表】和 HashMap 类类似,实现了 Map 接口。


HashTable 类内部所有方法都是同步(synchronized) 的,因此线程安全。但由于整个哈希存储区域共享一把锁,高并发场景下非常容易阻塞,性能很差。

ConcurrentHashMap 类

【哈希表】和 HashMap 类类似,实现了 Map 接口。


并发控制使用 synchronized 和 CAS 来操作,采取分段锁机制。synchronized 对哈希存储区域的每个 key 分别上锁,只锁定当前链表或红黑二叉树的首节点,这样只要不发生哈希冲突就不会产生并发,效率大大提升。


JDK 1.7 中, ConcurrentHashMap 类中包含静态内部类 Segment,继承于 ReentrantLock 类用来充当锁的角色,每个 Segment 对象守护若干个保存键值对的链表,共同构成 ConcurrentHashMap 实例中的数组。在 HashEntry 类中,key,hash 和 next 域都被声明为 final 型,value 域被声明为 volatile 型。由于 HashEntry 的 next 域为 final 型,所以新节点只能在链表的表头处插入。


JDK 1.8 中放弃了 Segment 臃肿的设计,取而代之的是采用 Node + CAS + Synchronized 来保证并发安全进行实现。


static final class HashEntry<K,V> {       final K key;                       // 声明 key 为 final 型       final int hash;                   // 声明 hash 值为 final 型       volatile V value;                 // 声明 value 为 volatile 型       final HashEntry<K,V> next;      // 声明 next 为 final 型
HashEntry(K key, int hash, HashEntry<K,V> next, V value) { this.key = key; this.hash = hash; this.next = next; this.value = value; }}Copy to clipboardErrorCopied
复制代码



普通容器转换

synchronizedList 方法

如果遇到多个线程操作同一个容器的场景,可以通过 Collections 工具类中的 synchronizedList 方法将其转换成线程安全的容器。


方法会被 synchronized 关键字重定义。

发布于: 刚刚阅读数: 4
用户头像

武师叔

关注

每天丰富自己,去过自己想要的生活! 2022.04.28 加入

一个喜欢最新技术,研发的人工智能专业的大二学生,用自己的代码做一些有意义的事情! 目前大二结束有去大厂研发岗实习的计划,每天丰富自己的技术,去过自己想要的实习生活。

评论

发布
暂无评论
Java—并发容器_6月月更_武师叔_InfoQ写作社区