ArrayBlockingQueue 源码分析
1. 概述
ArrayBlockingQueue
是 Java 中的一个阻塞队列实现,它基于数组实现,并提供了一个固定大小的容量。该队列在多线程环境下提供了线程安全的 put
和 take
操作,用于实现生产者-消费者模型。它的主要特点是通过数组来存储元素,并且支持阻塞操作,既可以在队列为空时等待,也可以在队列满时等待。
ArrayBlockingQueue
是一个 有界队列,它的容量在创建时就被固定,并且提供了如下操作:
ArrayBlockingQueue
是 Java 中的一个阻塞队列实现,它基于数组实现,并提供了一个固定大小的容量。该队列在多线程环境下提供了线程安全的 put
和 take
操作,用于实现生产者-消费者模型。它的主要特点是通过数组来存储元素,并且支持阻塞操作,既可以在队列为空时等待,也可以在队列满时等待。
ArrayBlockingQueue
是一个 有界队列,它的容量在创建时就被固定,并且提供了如下操作:
ArrayList
概述ArrayList
是 Java 集合框架中实现 List
接口的动态数组类。它的特点是:
elementData
存储元素。ArrayList
适合读多写少的场景,尤其是需要随机访问的情况。
ConcurrentHashMap
是 Java 集合框架中一个线程安全的 Map
实现类,主要用于高并发场景。相比 HashMap
,ConcurrentHashMap
采用了锁分段和无锁优化策略,在多线程环境下提供高效的键值对操作。ConcurrentHashMap
的实现因 JDK 版本不同而有所变化,以下以 Java 8 为主要分析版本。
CopyOnWriteArrayList
是 Java 中的一个线程安全的 List 实现,它使用了“写时复制”策略来保证线程安全。这意味着每次对列表进行修改(如添加、删除或更新元素)时,它都会复制原列表并在副本上进行操作,而不是直接在原列表上进行修改。这样可以确保多个线程能够安全地并发读取列表,而无需进行同步。
CopyOnWriteArrayList
的设计旨在优化读操作,适用于读多写少的场景,避免了传统同步方法(如 synchronized
或 ReentrantLock
)的性能瓶颈。
DelayQueue
是 Java 中的一个无界阻塞队列实现,继承自 AbstractQueue
,用于存储实现了 Delayed
接口的元素。队列中的元素在到期之前无法被取出,只有到期的元素才能从队列中获取。DelayQueue
通常用于需要定时任务调度或延时处理的场景,例如缓存超时处理和任务调度。
DelayQueue
的底层是一个 基于二叉堆的优先级队列,类似于 PriorityQueue
。它利用元素的 getDelay
方法计算剩余延时时间,按照到期时间的顺序进行排序。
HashMap
是一个基于哈希表实现的 Map
接口,它存储键值对 (key-value) 的映射关系。它允许键和值为 null
,并且是线程不安全的。HashMap
提供了常数时间的查找、插入和删除操作,前提是哈希函数分布均匀。
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
// 成员变量和方法
}
《阿里巴巴 Java 开发手册》的描述如下:
判断所有集合内部的元素是否为空,使用
isEmpty()
方法,而不是size()==0
的方式。
isEmpty()
方法的时间复杂度为 O(1)
,且可读性更高。而部分集合的 size()
方法的时间复杂度可能为 O(n)
,例如 java.util.concurrent
包下的 ConcurrentLinkedQueue
:
在 Java 中,集合(Collection) 是一种用于存储和操作数据的框架。它是 Java 标准库的一部分,定义了用于存储和操作对象的类和接口的集合。集合提供了很多方法,使得数据的存储、访问、插入、删除等操作变得更加简便和高效。
Java 集合分为两大类:
HashMap
和 Hashtable
的区别HashMap
和 Hashtable
都是基于哈希表的实现,但它们在多个方面有所不同,下面是这两者的详细对比:
线程安全性
HashMap
:是非线程安全的。多个线程同时访问 HashMap
,并且其中一个线程修改了 Map
,需要外部进行同步控制来保证线程安全。Hashtable
:是线程安全的。Hashtable
的方法大多都使用 synchronized
关键字进行了同步,从而确保在多线程环境下访问时是安全的。但这种同步机制会影响性能,导致 Hashtable
在大多数情况下比 HashMap
慢。效率
HashMap
:由于没有内置的同步机制,HashMap
的性能通常比 Hashtable
更高。HashMap
更适合在单线程环境下使用,或者在外部有明确同步控制的多线程环境下使用。Hashtable
:由于使用了 synchronized
进行同步,其性能相对较低,因此 Hashtable
在现代 Java 开发中不再推荐使用。对 null
键和值的支持
HashMap
:可以存储一个 null
键和多个 null
值。即,null
可以作为键,也可以作为值。Hashtable
:不允许存储 null
键或 null
值。如果尝试存储 null
键或 null
值,Hashtable
会抛出 NullPointerException
。初始容量和扩容策略
HashMap
:默认初始容量为 16,每次扩容为原来容量的 2 倍。可以通过构造函数传入自定义的初始容量和负载因子(默认为 0.75)。Hashtable
:默认初始容量为 11,每次扩容时容量变为原来的 2n + 1
,即不是 2 的幂次方。例如,HashMap
的构造函数:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
tableSizeFor
方法确保了 HashMap
使用 2 的幂作为哈希表的容量:
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
底层数据结构
HashMap
:JDK 1.8 之后,当哈希冲突的链表长度超过 8 时,HashMap
会将链表转换为红黑树,以提高查找效率。此举减少了在哈希冲突严重时的时间复杂度,从 O(n) 降低至 O(log n)。Hashtable
:Hashtable
没有使用红黑树来优化哈希冲突,它依然使用链表进行冲突处理,因此查找性能较低,尤其在哈希冲突严重时。哈希函数的实现
HashMap
:对键的哈希值进行了扰动处理(即通过对高位和低位进行混合扰动),以减少哈希冲突,提升性能。Hashtable
:直接使用键的 hashCode()
值,没有额外的扰动处理,可能导致更多的哈希冲突,影响性能。LinkedHashMap
是 Java 中的一个哈希表和链表实现,继承自 HashMap
,提供了在遍历时保持元素插入顺序或访问顺序的特性。它具有 HashMap
的所有优点,并且维护了元素的顺序,适用于需要按插入顺序或访问顺序遍历元素的场景。
LinkedHashMap
主要由以下两部分组成: