JUC 入门
前言
发现自己一直没有系统地学习 JUC。这篇博客仅作为学习过程中的记录所用。
JUC 指的是 java.util.concurrent
。此包的出现是为了更好的支持多线程、高并发任务。
线程基础
线程有六个状态:NEW
,RUNNABLE
,BLOCKED
,WAITING
,TIMED_WATTING
,TERMINATED
。
JUC 的结构
JUC 包含以下内容:Synchronization Utilities
(同步工具),Thread Pools
(线程池),Concurrent Collections
(并发集合),Locks
(锁),Atomic Variables
(原子变量)。
Synchronization Utilities
即同步工具类。包含:CountDownLatch
(闭锁)、CyclicBarrier
(栅栏)、Semaphore
(信号量)、Exchanger
(交换者)。
CountDownLatch
CountDownLatch
定义了一个计数器和一个阻塞队列。 当计数器的值递减为 0 之前,阻塞队列里面的线程处于挂起状态,当计数器递减到 0 时会唤醒阻塞队列所有线程。
CyclicBarrier
CyclicBarrier
允许一组线程互相等待,直到所有线程都到达一个共同的屏障点,然后所有线程才能继续执行。与 CountDownLatch
不同的是,CyclicBarrier
可以被重置并重复使用。
Semaphore
Semaphore
维护了一组 permits
,线程在进入临界区之前必须从 Semaphore
获取 permits
,当退出临界区时释放 permits
。permits
的数量决定了可以同时访问资源的线程数。Semaphore
既可以作为互斥锁(类似 ReentrantLock
),也可以用于限制并发量。
Exchanger
Exchanger
提供了一个同步点,两个线程在这个同步点上交换数据。当一个线程调用 exchange
方法时,它会进入等待状态,直到另一个线程也调用 exchange
方法。然后两个线程交换数据并继续执行。
Thread Pools
用于管理和复用一组线程,以执行异步任务。线程池通过预先创建一定数量的线程并将其保存在池中,任务提交时,线程池会将任务分配给池中的线程执行。任务完成后,线程不会被销毁,而是返回到池中,等待下一个任务。
常见的线程池类型:FixedThreadPool
、CachedThreadPool
、SingleThreadExecutor
、ScheduledThreadPool
、WorkStealingPool
。
FixedThreadPool
创建一个固定大小的线程池,线程数量是固定的。
当任务被提交时,如果有空闲线程,任务会立即执行。如果没有空闲线程,任务会被放入一个等待队列中,等待线程空闲时执行。线程池中的线程数量是固定的,不会因为任务的增加而增加,也不会因为任务的减少而减少。
CachedThreadPool
适用于需要执行大量短期异步任务的场景。
当任务被提交时,如果有空闲线程,任务会立即执行。如果没有空闲线程,线程池会创建新线程来处理任务。线程空闲时会被保留一段时间(默认 60 秒),如果在这段时间内没有新任务,它们会被终止并从池中移除。
SingleThreadExecutor
创建一个单线程执行器,以确保所有任务按顺序在同一个线程中执行。
SingleThreadExecutor
内部维护一个单一的工作线程。当任务被提交时,如果工作线程空闲,任务会立即执行。如果工作线程正在执行任务,新提交的任务会被放入一个等待队列中,按照提交顺序依次执行。即使在出现异常时,线程池也会保证顺序执行下一个任务。
ScheduledThreadPool
允许任务在预定的延迟后执行,也可以按照固定的频率重复执行。
ScheduledThreadPool
内部维护一个线程池和一个任务队列。可以使用 schedule
方法提交延迟执行的任务,或使用 scheduleAtFixedRate
和 scheduleWithFixedDelay
方法提交周期性执行的任务。schedule
方法允许任务在指定的延迟时间后执行一次。scheduleAtFixedRate
方法允许任务以固定的频率重复执行,无论任务执行时间长短。scheduleWithFixedDelay
方法允许任务在前一个任务完成后,经过固定的延迟时间后再执行。
WorkStealingPool
使用工作窃取(work stealing)算法来提高并行任务的执行效率。
WorkStealingPool
内部维护了一个线程池,每个线程都有自己的工作队列。当一个线程完成了自己的任务后,它会去其他线程的工作队列中偷取任务来执行,这样可以有效地避免线程空闲。工作窃取算法使得任务的执行更加高效,特别适用于处理递归式、可分解的任务。
Concurrent Collections
并发集合是一组线程安全的集合类,用于在多线程环境下进行数据共享和并发访问。这些集合类提供了高效的并发访问机制,可以在不需要显式同步的情况下安全地在多个线程之间共享数据。
常见的并发集合类:ConcurrentHashMap
、ConcurrentSkipListMap
、ConcurrentSkipListSet
、ConcurrentSkipListSet
、CopyOnWriteArraySet
、ConcurrentLinkedQueue
、ConcurrentLinkedDeque
等。
ConcurrentHashMap
HashMap
的线程安全版本。其不允许键或值为 null
。提供了线程安全的迭代器。
ConcurrentHashMap
使用分段锁算法,提高并发性能。
ConcurrentSkipListMap
是一种随机化的数据结构,通过跳表实现。
ConcurrentSkipListMap
的 key
是有序的,支持更高的并发。