JUC概览

2023/12/16 Java多线程与并发-JUC

JUC(Java Util Concurrent)是指Java并发编程工具包,它提供了一些在并发编程中非常有用的类和接口。JUC包含了更加高级和灵活的并发编程工具,相对于传统的Thread类和synchronized关键字提供了更加强大和可靠的并发编程解决方案。

JUC包含:Lock框架、Tool类、并发合集、原子类、线程池。

JUC类图:

# 1、Lock框架

Lock框架指的是java.util.concurrent.locks包下提供的一组锁实现。该框架提供了比传统的synchronized关键字更灵活和功能更强大的锁机制,可以用于实现更高效的多线程编程。

# 1.1、Condition接口

Condition接口用于在锁上创建一个或多个绑定的条件,用于线程之间的协调和通信。可以通过Lock对象的newCondition()方法创建Condition对象。

# 1.2、Lock接口

Lock接口是定义了锁的基本方法的接口。常用的实现类包括ReentrantLock、ReentrantReadWriteLock等。

# 1.3、ReadWriteLock接口

ReadWriteLock接口提供了读写锁的操作方法。主要有读锁和写锁两个操作,读锁支持多个线程同时读取共享资源,写锁同一时间只允许一个线程写入共享资源。

# 1.4、抽象类

AbstractOwnableSynchonizer

AbstractOwnableSynchronizer是一个抽象类,主要为其他锁和同步器提供了统一的独占模式的线程所有权管理功能。

AbstractQueuedLongSynchronizer

AbstractQueuedLongSynchronizer 是一个抽象类,它为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(如重入锁、信号量等)提供了一个框架。

AbstractQueuedSynchronizer(AQS)

  • AbstractQueuedSynchronizer是Lock框架的核心组件,它提供了底层的同步机制,为具体的锁实现类(例如ReentrantLock、ReentrantReadWriteLock)提供了基础。
  • AbstractQueuedSynchronizer定义了一种具有独占性的同步器,可以支持自定义的同步器实现。它提供了一套基于FIFO等待队列的同步机制,用于管理线程的获取和释放锁。它内部维护了一个FIFO的双向链表,用于存储等待获取锁的线程。

# 1.5、LockSupport类

LockSupport提供了线程阻塞和唤醒的机制。它可以代替传统的Object类的wait()和notify()方法来实现线程间的同步和协作。

# 1.6、ReentrantLock类

ReentrantLock是一个重入锁的实现类,它实现了Lock接口,提供了与内置的synchronized关键字相似的功能,但更加灵活和可扩展。

# 1.7、ReentrantReadWriteLock类

ReentrantReadWriteLock是一个重入读写锁的实现类,它实现了Lock接口,并在Lock的基础上提供了更高级别的读写锁功能。

# 1.8、StampedLock类

StampedLock是Java 8中新增的一个锁类,它提供了乐观读锁、悲观读锁和写锁的支持。StampedLock的设计目标是在读多写少的情况下,提供更高的并发性能。

# 2、Tool类

Tool类是一个包含CountDownLatch、CyclicBarrier、Semaphore、Exchanger、Phaser等类的并发包,提供了一系列高级同步工具,用于帮助开发者更好地进行精细化的并发控制。

# 2.1、CountDownLatch类

CountDownLatch允许一个或多个线程等待其它一组线程完成操作后才能继续执行。

# 2.2、CyclicBarrier类

  • CyclicBarrier允许一组线程在达到一个同步点(barrier)后再一起继续执行。这个同步点就是通过CyclicBarrier设定的一个整数,当等待的线程数量达到这个数值时,就表示barrier被打破,所有在等待的线程将被唤醒继续执行。
  • CyclicBarrier比CountDownLatch更加复杂,但功能也更加强大,它可以允许同步点的数量动态改变,还可以被重置和重复使用。

# 2.3、Phaser类

  • Phaser允许多个线程在多个阶段之间进行协同和同步操作。
  • Phaser 的一个重要特点是,它不像 CountDownLatch 那样只能使用一次,也不像 CyclicBarrier 那样需要在重新使用前调用 reset() 方法,它可以自动等待新的阶段。

# 2.4、Semaphore类

Semaphore(信号量)用于限制可以访问某些资源(物理或逻辑的)的线程数目。实质上,Semaphore管理了一个许可集,线程可以通过acquire()方法获取许可,当许可用时,线程可以继续执行,否则线程可能会阻塞等待直到许可可用。线程完成操作后,需要通过release()方法释放许可。

# 2.5、Exchanger类

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。

# 3、并发集合

并发集合提供了一些线程安全的集合类。这些类在执行读、写操作时不需要额外的同步或加锁操作,已在内部处理了线程安全。

并发集合类图

# 3.1、Queue

BlockingQueue

  • ArrayBlockingQueue:一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序,并且在尝试添加元素到满队列或从空队列中获取元素时,线程会被阻塞。
  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,同样遵循先进先出(FIFO)的原则进行元素的操作。
  • LinkedBlockingDeque:一个基于双向链表实现的双端阻塞队列,不仅可以从头部插入/移除元素,也可以从尾部插入/移除元素。

ConcurrentLinkedQueue

  • ConcurrentLinkedQueue:一个基于链接节点的无界线程安全队列。

其他队列

  • ConcurrentLinkedDeque: 一个基于链接节点的无界线程安全双端队列,采用先进先出的原则对元素进行排序,适合高并发场景。
  • DelayQueue: 一个由延迟元素构成的无界阻塞队列,只有在延迟期满时才能从队列中提取元素,适用于任务调度等需要延时处理的场景。
  • PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,元素按优先级顺序出队,同优先级元素则按照插入顺序排序。
  • SynchronousQueue: 一种无缓冲的等待队列,也就是传递性阻塞队列,它的每一个插入操作必须等待另一个线程进行相应的删除操作,反之亦然。
  • LinkedTransferQueue: 一种链表组织的无界阻塞TransferQueue(可转移队列),它比其他并发队列多了transfer()和tryTransfer()方法,可以将元素直接传递给消费者进行处理。

# 3.2、List

CopyOnWriteArrayList

CopyOnWriteArrayList的"CopyOnWrite"翻译为"写入时复制",意味着每次对list的修改(如add、set),都会创建list的全新复制副本,读操作则基于较早的数据版本进行,这就是线程安全的体现。

# 3.3、Set

CopyOnWriteArraySet

CopyOnWriteArraySet是一种线程安全的Set实现类,"CopyOnWrite"的含义是"写入时复制",也就是说,每次对Set的修改(如add、remove等),都会创建Set的全新复制副本,而读操作则基于较早的数据版本进行,这就是线程安全的体现。

ConcurrentSkipListSet

ConcurrentSkipListSet是线程安全的排序集合实现类。它底层是基于ConcurrentSkipListMap实现的,所有元素都是按照自然排序(自定义比较器也可)进行排列。

# 3.4、Map

ConcurrentHashMap

ConcurrentHashMap可以支持多个线程同时进行写操作,并且有较高的并发性。它是通过初始的分段(Segment)锁实现的,每个分段都可以独立进行并发写操作,从而实现并发性。

ConcurrentSkipListMap

ConcurrentSkipListMap的主要特性是它是线程安全的同时还是有序的,它的内部实现是基于跳表数据结构。跳表是一种随机化的数据结构,效率高且并发性强。

# 4、原子类

原子类,如AtomicInteger、AtomicLong、AtomicReference等,是一组利用CAS(compare-and-swap)操作提供的线程安全的数值操作类,用于进行原子级别的数值运算,避免了显式使用同步锁的需要。

# 4.1、基础类型

AtomicBoolean,AtomicInteger,AtomicLong

# 4.2、数组

AtomicIntegerArray,AtomicLongArray,BooleanArray

# 4.2、引用

AtomicReference,AtomicMarkedReference,AtomicStampedReference

# 4.2、FieldUpdater

AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater

# 5、线程池

线程池是一种创建和管理线程的机制,它可以控制运行中的线程数量,处理过程中将任务放入队列,然后在任务完成后,将线程返回给线程池,以备再次利用。

线程池类图

# 5.1、接口与抽象类

Executor

Executor接口为任务的提交和任务的执行提供了一个解耦的框架,用来管理和控制线程执行任务的过程。

ExecutorService

ExecutorService接口是用来管理和控制多个线程执行任务的框架。它提供了一种简单方便的方式来创建、执行和关闭线程池,并且可以跟踪任务的执行状态和结果。通过使用ExecutorService,我们可以将任务提交给线程池执行,并且可以灵活地控制线程的数量和调度方式。

ScheduledExecutorService

  • ScheduledExecutorService是ExecutorService的一个子接口,它提供了一种可以按照指定的时间间隔或者延迟执行任务的能力。
  • ScheduledExecutorService可以用来执行周期性的任务、延时任务以及定时任务。它相比于普通的ExecutorService,增加了定时执行任务的功能,可以根据需要自动地执行任务,不需要手动调用或者等待。通过ScheduledExecutorService,我们可以方便地在指定的时间间隔内执行任务,或者在指定的延时后执行任务。这个接口使得任务的调度变得更加方便和准确,适用于需要按照固定时间或者间隔来执行的任务场景。

AbstractExecutorService

  • AbstractExecutorService是一个实现了ExecutorService接口的抽象类,它提供了一些默认的实现和方法,方便其他具体的ExecutorService实现类继承和扩展。
  • AbstractExecutorService定义了一些基本的方法,如submit()、invokeAll()、invokeAny()等接口方法的默认实现。它还提供了一些辅助方法,如newTaskFor()、newTaskFor()等,用于创建新的任务和执行器。

# 5.2、FutureTask

  • FutureTask是Java中的一个实现了Future接口和Runnable接口的类,它表示一个可取消的异步计算任务。
  • FutureTask通过包装一个Callable或Runnable任务,可以在任务执行完成后获取结果或取消任务。
  • FutureTask可以用来表示一个有返回值的任务,当任务执行完成后,可以通过调用它的get()方法获取结果。如果任务还没有执行完成,get()方法会阻塞直到任务执行完成并返回结果。
  • FutureTask还可以用来表示一个无返回值的任务,可以直接调用它的run()方法执行任务。此外,FutureTask还提供了一些其他方法,如cancel()方法用于取消任务的执行,isDone()方法用于判断任务是否已经完成。
  • FutureTask可以被用作一个可重复执行的任务,通过调用它的run()方法,任务会被执行一次。同时,它也可以通过传递给ExecutorService执行器来异步执行,并通过get()方法获取结果或阻塞等待任务的执行完成。

# 5.3、ThreadPoolExecutor

ThreadPoolExecutor实现了AbstractExecutorService接口,也是一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置。 线程池可以解决两个不同问题: 由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。

# 5.4、ScheduledThreadExecutor

ScheduledThreadPoolExecutor实现ScheduledExecutorService接口,可安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于 Timer。

# 5.5、Fork/Join框架

Fork/Join 技术是分治算法(Divide-and-Conquer)的并行实现,它是一项可以获得良好的并行性能的简单且高效的设计技术。目的是为了帮助我们更好地利用多处理器带来的好处,使用所有可用的运算能力来提升应用的性能。

# 5.6、Executors

Executors是一个工具类,用其可以创建ExecutorService、ScheduledExecutorService、ThreadFactory、Callable等对象。它的使用融入到了ThreadPoolExecutor, ScheduledThreadExecutor和ForkJoinPool中。