Java Concurrent 包
并发编程中通用的工具类。包括一些标准化,可扩展的小的实现结构(框架),和一些实用但却枯燥且不易实现的工具类。以下为主要组件的简易描述。另参考 java.util.concurrent.locks 和 java.util.atomic 包。
执行器(Executors)
接口(Interfaces):Executor 是一个标准化的接口,用于定义用户线程类的子系统,包括线程池,异步IO和轻量级任务框架。任务是通过新建线程,已存在的线程,或调用了执行方法的线程,是顺序还是并行执行取决于正在使用的 Executor 类。ExecutorServie 接口提供了一个完整的异步任务执行方案。ExecutorServie 管理任务的执行顺序和调度,并且关闭可控。ScheduledExecutorServie 子接口及其辅助接口提供了对任务延迟和定时执行的支持。ScheduledExecutorServie 还提供了类似于 Callable 这种异步执行且能返回结果的方法,好比携带返回结果的 Runnable 接口。通过 Future 接口返回执行结果,可以判定任务是否结束,并提供了取消任务的手段。RunnableFuture 接口提供了 run 方法并根据执行结果设置返回值。
实现(Implementations):ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 类提供了弹性可调的线程池。Executors 类提供了工厂方法来创建通用的执行器(Executor),并配以一些工具类方法来使用这些执行器。其他以 Executors 为基础的工具类包括 FutureTask (Future 的通用扩展)和 ExecutorCompletionService (致力于以组为单位的异步任务之间的协同合作)。
ForkJoinPool 提供了用来处理 ForJoinTask 及其子类的 Executor 的一种原生设计实现。它使用工作窃取调度器使得执行受并行处理计算密集型限制的任务时获得高吞吐量表现。
队列(Queues)
ConCurrentLinkedQueue 提供了一种高效,可扩展的,非阻塞的先进先出队列。与 Deque 接口类似但更强大。
对于 BlockingQueue 这种定义阻塞版本的存取接口在 java.util.concurrent 包中提供五种实现:LinkedBlockingQueue, ArrayBlockingQueue, SynchronousQueue, PriorityBlockingQueue, and DelayQueue。这些不同的实现覆盖了生产者-消费者,消息,并行作业,以及并发相关设计的大多数场景。
TransferQueue 接口及其实现类 LinkedTransferQueue 引入了同步传输方法(及其相关特性),允许生产者可选择地阻塞等待消费者。
BlockingDeque 接口继承于 BlockingQueue,支持先进先出和后进先出(基于栈)的操作。LinkedBlockingDeque 是其实现。
时间(Timing)
TimeUnit 类提供了包括毫秒级的多粒度单位,用于指定和控制超时时间。除不确定等待外,包中大多数类都是基于超时时间来运作的。在所有使用超时时间的情况中,超时时间指明了方法超时的最小时间。当超时发生时会尽“最大努力”去检测,但在超时发生和被检测到,这中间的时间是不确定的,在这个过程中线程有可能在超时之后再次执行。所有接受超时时间参数的方法会将小于等于零的值视为不等待。如果想让等待“趋于无限”则可以传 Long.MAX_VALUE 值。
同步器(Synchronizers)
五个特殊场景的同步机制通用实现类:
- Semaphore 是一个经典的并发工具类;
- CountDownLatch 一个非常简单但常用的工具,适合于阻塞直到给定的信号量,事件或条件的场景;
- CiclicBarrier 是一个可重置的多路同步点,在并行编程风格中非常有用;
- Phaser 提供了一种更加弹性的屏障形式,在多线程分段计算控制场景中可能会用到;
- Exchanger 允许两个线程在一个会合点交换对象,这在多管道设计模式中非常有用。
并发集合(Concurrent Collections)
除队列外,这个包还提供了集合的实现,以供多线程上下文环境中使用:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和CopyOnWriteArraySet。当多个线程访问一个给定的集合时,ConcurrentHashMap 相对于加同步锁的 HashMap 更为合适,ConcurrentSkipListMap 通常会比加同步锁的 TreeMap 效果更佳。当预期的读取和遍历次数远远多于列表更新的次数时 CopyOnWriteArrayList 比同步状态下的 ArrayList 效果更好。
以上几个类中以 “Concurrent(并发)” 作为前缀意在与类似的 “synchronized” 类进行区分。比如 java.util.HashTable 和 Collections.synchronizedMap(new HashMap()) 是同步,但 ConcurrentHashMap 则是并发。并发集合是线程安全的,但并不是由互斥锁来管理并发。在特定情况下,ConcurrentHashMap 保证了任意数量并发读取和大量并发写入的安全。当你需要使用锁来控制多个线程对同一集合时“同步”类会非常有用,但代价是牺牲了扩展性。在其它多线程访问同一集合的情况“并发”版本会通常更有用。当集合数据是共享或持有其它锁的线程才能访问时非同步集合更为合适。
大多数并发集合(包括大部分队列)不同于常用的 java.util 包惯例,它们的迭代器和分隔器提供了弱一致而不是快速失败的遍历,比如:
- 可以与其它操作并行执行;
- 不会抛出 ConcurrentModificationException 异常;
- 保证只遍历一次在集合创建时就存在的元素,可能(但不保证)反映任意修改信息。
内存一致性
在 Java 语言规范的第17章中定义了关于内存中共享变量读写的 happens-before 原则。即当一个线程对同一变量的写操作仅在先于另一线程读操作发生时,其结果对读操作是可见的。“synchronized” 和 “volatile”实现 以及 Thread.start() 和 Thread.join() 方法存有 happens-before 关系。如:
- 同一线程中按照编码顺序前一操作优先于后一操作执行;
- 同一监视器的解锁(同步块或方法退出)优先于后续对这个监视器的加锁(同步块或方法进入)。并且因为 happens-before 原则具有传播性,所有线程对这一监视器的解锁操作都优先于后续任意线程对其加锁操作;
- 对 volatile 变量的写操作都优先于后续的读操作;对于 volatile 变量的读写和对监视器的持有和释放有类似的内存一致性,但不需要使用互斥锁;
- 线程的开始优先于线程内的任意操作;
- 线程内的所有操作优先于其它线程成功从该线程的 join 操作返回。
并发包(java.util.concurrent)及其子包中所有类方法沿用以上规则并扩展至更高级别的同步机制。例如:
- 并发集合中插入一个元素优先于其它线程对该元素的读取和删除;
- 提交一个 Runnable 给 Executor 优先于这个 Runnable 执行;提交 Callable 给 ExecutorService 同理;
- 对于 Future 的异步计算操作优先于后续其他线程通过 Future.get() 方法对结果进行读取;
- 同一同步器的释放操作,比如 Lock.unlock,Semaphore.release,和 CountDownLatch.countDown 优先于后续其它线程对其进行加锁的操作,如 Lock.lock,Semaphore.acquire,Condition.await 和 CountDownLatch.await。
- 对于通过 Exchanger 成功交换对象的一对线程来说,每个线程内先发生的 exchange() 优先于后续另一线程内的 exchange() ;
- 调用屏障的操作(如 CyclicBarrier.await 和 Phaser.awaitAdvance 及其变体)优先于屏障操作本身,而屏障操作本身则优先于其它线程调用屏障的成功返回。
详情参考 Java 语言规范:17.4.5 Happens-before Order 。
包 | 描述 |
---|---|
java.util | 包含集合框架,国际化支持类,服务加载器,属性,随机数生成器,字符解析和类扫描,base64 编码和解码,位数组,以及一些工具类。 |
java.util.concurrent.atomic | 支持对单变量无锁且线程安全地操作的工具包 |
java.util.concurrent.locks | 包括了对锁和等待机制实现的类和接口,有别于内置的同步器和监视器。 |
类 | 描述 |
---|---|
AbstractExecutorService | 提供了 ExecutorService 执行方法的默认实现。 |
ArrayBlockingQueue | 基于数组实现的有界队列。 |
BlockingDeque | 一个双端队列,除了支持常规操作外,还支持阻塞操作。在获取元素时,如果队列为空,则等待队列非空;在存储元素时,如果队列已满,则等待队列有可用空间。 |
BlockingQueue | 队列,除了支持常规操作外,还支持在获取元素时等待队列非空,以及在存储元素时等待队列有可用空间的操作。 |
BrokenBarrierException | 当一个线程试图在一个已经处于故障状态的屏障上等待,或者在该线程等待期间屏障进入故障状态时抛出的异常。 |
Callable | 一个返回结果并可能抛出异常的任务。 |
CancellationException | 异常指示由于任务被取消,无法获取值生成任务(如FutureTask)的结果。 |
CompletableFuture | 一个可能明确完成的未来(设置其值和状态),可以作为CompletionStage使用,支持在其完成后触发依赖函数和操作。 |
CompletableFuture.AsynchronousCompletionTask | 一个标记接口,用于标识由异步方法生成的异步任务。 |
CompletionException | 在完成结果或任务的过程中遇到错误或其他异常时抛出的异常。 |
CompletionService | 一种服务,将新异步任务的生成与已完成任务结果的消费解耦。 |
CompletionStage | 一个可能异步计算的阶段,在另一个CompletionStage完成时执行操作或计算值。 |
ConcurrentHashMap<K,V> | 支持完全并发检索和高预期并发更新的哈希表。 |
ConcurrentHashMap.KeySetView<K,V> | 将ConcurrentHashMap视为一个键的集合,其中可选择通过映射到一个公共值来启用添加。 |
ConcurrentLinkedDeque | 基于链式节点的无界并发双端队列。 |
ConcurrentLinkedQueue | 基于链式节点的无界并发队列。 |
ConcurrentMap<K,V> | 提供线程安全性和原子性保证的地图。 |
ConcurrentNavigableMap<K,V> | 一个支持NavigableMap操作的ConcurrentMap,并且其可导航子映射也递归支持这些操作。 |
ConcurrentSkipListMap<K,V> | 一种可扩展的并发NavigableMap实现。 |
ConcurrentSkipListSet | 一种基于并发跳表的可扩展并发NavigableSet实现。 |
CopyOnWriteArrayList | 一种线程安全的ArrayList变体,其中所有可变操作(如添加、设置等)都是通过创建底层数组的新副本来实现的。 |
CopyOnWriteArraySet | 一个使用内部CopyOnWriteArrayList进行所有操作的集合。 |
CountDownLatch | 一种同步辅助工具,允许一个或多个线程等待,直到其他线程中执行的一组操作完成。 |
CountedCompleter | 一个ForkJoinTask,在触发时且没有剩余待执行操作的情况下,会执行其完成动作。 |
CyclicBarrier | 一种同步辅助工具,允许一组线程都等待其他线程到达共同的屏障点。 |
Delayed | 一种混合式接口,用于标记应在给定延迟后进行操作的对象。 |
DelayQueue | 一个无界阻塞队列,其中包含延迟元素,只有当元素的延迟期满时才能被取出。 |
Exchanger | 一个同步点,在此点上线程可以配对并在配对之间交换元素。 |
ExecutionException | 在尝试获取一个因抛出异常而中止的任务的结果时抛出的异常。 |
Executor | 一个执行提交的Runnable任务的对象。 |
ExecutorCompletionService | 一个使用提供的Executor来执行任务的CompletionService。 |
Executors | 本包中定义了Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和Callable类的工厂方法和工具方法。 |
ExecutorService | 一个执行器,提供管理终止的方法,并且可以生成一个Future对象来跟踪一个或多个异步任务的进度。 |
Flow | 互相关联的接口和静态方法,用于建立流控组件,在这些组件中,发布者生成项目,由一个或多个订阅者消费,每个订阅者都由一个订阅管理。 |
Flow.Processor<T,R> | 一个既充当订阅者又充当发布者的组件。 |
Flow.Publisher | 一个生产者,负责生成被订阅者接收的项目(及相关控制消息)。 |
Flow.Subscriber | 信息接收者 |
Flow.Subscription | 消息控制连接一个Flow.Publisher和Flow.Subscriber。 |
ForkJoinPool | 用于运行ForkJoinTask的ExecutorService。 |
ForkJoinPool.ForkJoinWorkerThreadFactory | 用于创建新ForkJoinWorkerThreads的工厂。 |
ForkJoinPool.ManagedBlocker | 用于扩展在ForkJoinPool中运行的任务的托管并行接口。 |
ForkJoinTask | 在ForkJoinPool中运行的任务的抽象基类。 |
ForkJoinWorkerThread | 由ForkJoinPool管理的线程,用于执行ForkJoinTask。 |
Future | 一个未来代表了一个异步计算的结果。 |
FutureTask | 一个可取消的异步计算。 |
LinkedBlockingDeque | 基于链接节点的可选有界阻塞双端队列。 |
LinkedBlockingQueue | 基于链接节点的可选有界阻塞队列。 |
LinkedTransferQueue | 基于链接节点的无界传输队列。 |
Phaser | 一个可重复使用的同步屏障,功能类似于CyclicBarrier和CountDownLatch,但支持更灵活的使用方式。 |
PriorityBlockingQueue | 一个无界阻塞队列,使用与PriorityQueue类相同的排序规则,并提供阻塞检索操作。 |
RecursiveAction | 一个无返回结果的递归ForkJoinTask。 |
RecursiveTask | 一个递归结果承载的ForkJoinTask。 |
RejectedExecutionException | 当任务无法被接受执行时,由执行器抛出的异常。 |
RejectedExecutionHandler | 一个用于处理无法由ThreadPoolExecutor执行的任务的处理器。 |
RunnableFuture | 一个可运行的未来。 |
RunnableScheduledFuture | 一个可运行的ScheduledFuture。 |
ScheduledExecutorService | 一个可以安排命令在给定延迟后执行,或者定期执行的ExecutorService。 |
ScheduledFuture | 一个可以取消的延迟生效的行为。 |
ScheduledThreadPoolExecutor | 一个可以额外安排在给定延迟后执行命令或定期执行任务的线程池执行器。 |
Semaphore | 计数信号量。 |
SubmissionPublisher | 一个Flow.Publisher,它异步地将提交的(非空)项发送给当前订阅者,直到它被关闭。 |
SynchronousQueue | 一个阻塞队列,其中每个插入操作必须等待另一个线程的相应删除操作,反之亦然。 |
ThreadFactory | 一个根据需求创建新线程的对象。 |
ThreadLocalRandom | 一个周期为2^64的随机数生成器,隔离在当前线程中。 |
ThreadPoolExecutor | 一个使用可能的多个池化线程之一来执行每个提交任务的ExecutorService,通常使用Executors工厂方法进行配置。 |
ThreadPoolExecutor.AbortPolicy | 一个处理被拒绝任务的处理器,会抛出RejectedExecutionException异常。 |
ThreadPoolExecutor.CallerRunsPolicy | 一个处理被拒绝任务的处理器,它会在执行方法调用线程中直接运行被拒绝的任务,除非执行器已被关闭,在这种情况下任务会被丢弃。 |
ThreadPoolExecutor.DiscardOldestPolicy | 一个处理被拒绝任务的处理器,它会丢弃最老的未处理请求,然后重试执行,除非执行器已关闭,在这种情况下任务会被丢弃。 |
ThreadPoolExecutor.DiscardPolicy | 一个处理被拒绝任务的处理器,它会默默地丢弃被拒绝的任务。 |
TimeoutException | 当阻塞操作超时时抛出的异常。 |
TimeUnit | TimeUnit 表示在特定粒度单位下的时间间隔,并提供在这些单位之间进行转换的实用方法,以及执行定时和延迟操作的功能。 |
TransferQueue | 一种阻塞队列,生产者可以在其中等待消费者接收元素。 |
注:以上只是对 Java 并发包的一个简单翻译,仅供参考。翻译一遍的目的主要是加深对 Java 并发包的理解。