【重难点总结】第三章 Java 并发包
文章目录
一、线程安全的集合类
1.ConcurrentHashMap
基本介绍
ConcurrentHashMap 和 HashMap 一样使用数组加链表或者数组加红黑树的数据结构,不同的是,ConcurrentHashMap 在桶上引入了锁来保证线程安全。
线程安全的实现
- CAS 操作:ConcurrentHashMap 在更新的时候使用了 CAS 来避免加锁,减少上下文切换的开销,提高并发性能
- Synchronized:当 CAS 尝试次数过多,为避免 CPU 被占用,会在链表头节点或者红黑树根节点加锁
扩容机制
相较于 HashMap,ConcurrentHashMap 引入了多线程协作扩容机制。每个线程会处理一部分桶的迁移哦给你做,并通过 CAS 操作来确保任务分配的原子性。
扩容时,新旧数组会同时存在,逐步将旧数组中的数据前移到新数组中。新插入的元素会直接插入到新数组,而不是旧数组。在扩容的过程中,新数组和旧数组通常是可以同时访问的,直到扩容完成,新数组才会完全替换旧数组。
2.CopyOnWriteArrayList
基本介绍
CopyOnWriteArrayList 是线程安全的,在对集合进行修改(添加、删除、修改)时,会创建一个新的数组,以保证不会影响到正在进行遍历操作的线程。这使得 CopyOnWriteArrayList 适用于读多写少的场景,因为写操作会导致创建新的数组,会消耗额外的内存和时间。
线程安全的实现
- 写时复制:写操作不修改原始数组,而是复制一个全新数组,不影响其他线程对原始数组的读操作
- volatile关键字:内部数组使用了 volatile 关键字修饰,这意味着任何线程的写操作对其他线程都是可见的
二、ArrayBlockingQueue
1.基本介绍
ArrayBlockingQueue 是Java 中的一个阻塞队列实现。它基于数组实现,并且在创建时必须指定其容量,一旦创建,其容量不能改变,避免高并发环境下扩容的复杂性,简化了并发控制,并提供高效可靠和可预测的性能。它支持公平和非公平的访问策略,用于在多线程环境中进行线程安全的元素存取操作。
在 ArrayBlockingQueue 内部,主要使用了一个数组来存储元素,以及两个指针来标记队列的头和尾。通过内部锁(ReentrantLock)和两个条件变量(notEmpty 和 notFull),来实现对队列的并发控制和阻塞操作。
2.主要特点
- 固定容量:ArrayBlockingQueue 在创建时需要指定容量,队列的大小是固定的,不能动态调整
- 阻塞行为:put 和 take 方法会阻塞,直到有容量可用或者有元素可取;offer 和 poll 不会一直阻塞,可以指定超时时间
- 线程安全:通过 ReentrantLock 保证了线程安全
- 可选公平性:可以在构造函数中指定是否使用公平锁
3.主要方法
- void put(E e) throws InterruptedException:将指定的元素插入到队列中,如果队列满,则等待
- boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException:将指定的元素插入到队列中,如果队列满,则等待指定的时间,如果超时仍未成功,则返回 false
- E take() throws InterruptedException:从队列中移除并返回队列头部的元素,如果队列为空,则等待
- E poll(long timeout, TimeUnit unit) throws InterruptedException:从队列中移除并返回队列头部的元素,如果队列为空,则等待指定的时间,如果超时仍未成功,则返回 null
- E peek():返回队列头部的元素,但不移除,如果队列为空,则返回 null
三、AbstractQueueSynchronizer
1.基本介绍
AbstractQueueSynchronizer(AQS)是 Java 并发包中实现高级同步工具的基础,它提供了一个灵活且高效的框架,通过状态管理、FIFO 等待队列和独占/共享模式,实现了多种复杂的同步器。通过子类化和实现特定的同步逻辑,开发者可以创建符合自己需求的同步器。
2.核心概念
- 同步状态(State):AQS使用一个 int 类型的变量来表示同步状态。该状态可以通过 getState(),setState(int newState) 和 compareAndSetState(int expect, int update) 方法进行操作
- FIFO 等待队列:AQS 使用一个 FIFO 队列来管理获取同步状态失败的线程。线程被封禁成一个节点(Node),并添加到队列中等待唤醒
- 独占模式和共享模式:独占模式下,同步器一次只允许一个线程持有锁,例如 ReentrantLock;共享模式下,同步器允许多个线程共享同步状态,例如 CountDownLatch 和 Semaphore
3.主要方法
独占模式相关方法:
- boolean tryAcquire(int arg):独占方式尝试获取同步状态。具体实现需要子类重写
- boolean tryRelease(int arg):独占方式尝试释放同步状态。具体实现需要子类重写
- void acquire(int arg):独占方式获取同步状态,如果获取失败则进入等待队列
- boolean release(int arg):独占方式释放同步状态,并唤醒等待队列中的一个线程
共享模式相关方法
- int tryAcquireShared(int arg):共享方式尝试获取同步状态。具体实现需要子类重写
- boolean tryReleaseShared(int arg):共享方式尝试释放同步状态。具体实现需要子类重写
- void acquireShared(int arg):共享方式获取同步状态,如果获取失败则进入等待队列
- boolean releaseShared(int arg):共享方式释放同步状态,并唤醒等待队列中的所有线程
<