模块 java.base

包 java.util.concurrent


java.util.concurrent
通常在并发编程中有用的实用程序类。这个包包括一些小的标准化可扩展框架,以及一些提供有用功能但单调乏味或难以实现的类。以下是主要组件的简要说明。另请参阅 java.util.concurrent.locks java.util.concurrent.atomic 包。

Executors

接口。Executor 是一个简单的标准化接口,用于定义自定义类线程子系统,包括线程池、异步 I/O 和轻量级任务框架。根据使用的具体 Executor 类,任务可能在新创建的线程、现有任务执行线程或调用 execute 的线程中执行,并且可能顺序执行或并发执行。 ExecutorService 提供了更完善的异步任务执行框架。 ExecutorService 管理任务的排队和调度,并允许受控关闭。 ScheduledExecutorService 子接口和相关接口增加了对延迟和周期性任务执行的支持。 ExecutorServices 提供方法来安排异步执行任何表示为 Callable 的函数,它是 Runnable 的结果承载类比。 Future 返回函数的结果,允许确定执行是否已完成,并提供取消执行的方法。 RunnableFuture 是一个 Future,它拥有一个 run 方法,该方法在执行时设置其结果。

实施。ThreadPoolExecutor ScheduledThreadPoolExecutor 提供可调的、灵活的线程池。 Executors 类为最常见的执行器类型和配置提供工厂方法,以及一些使用它们的实用方法。其他基于 Executors 的实用程序包括具体类 FutureTask 提供 Futures 的通用可扩展实现,以及 ExecutorCompletionService ,它有助于协调异步任务组的处理。

ForkJoinPool 提供了一个执行器,主要用于处理 ForkJoinTask 及其子类的实例。这些类采用工作窃取调度程序,为符合计算密集型并行处理中通常存在的限制的任务实现高吞吐量。

队列

ConcurrentLinkedQueue 类提供了一个高效的可扩展线程安全非阻塞 FIFO 队列。 ConcurrentLinkedDeque 类类似,但还支持 Deque 接口。

java.util.concurrent 中的五个实现支持扩展的 BlockingQueue 接口,它定义了 put 和 take 的阻塞版本:LinkedBlockingQueue ArrayBlockingQueue SynchronousQueue PriorityBlockingQueue DelayQueue 。不同的类涵盖了生产者-消费者、消息传递、并行任务处理和相关并发设计的最常见使用上下文。

扩展接口 TransferQueue 和实现 LinkedTransferQueue 引入同步 transfer 方法(以及相关功能),其中生产者可以选择阻塞等待其消费者。

BlockingDeque 接口扩展了 BlockingQueue 以支持 FIFO 和 LIFO(基于堆栈)操作。类 LinkedBlockingDeque 提供了一个实现。

定时

TimeUnit 类提供了多种粒度(包括纳秒)来指定和控制基于超时的操作。除了无限期等待之外,包中的大多数类都包含基于超时的操作。在所有使用超时的情况下,超时指定方法在指示其超时之前应等待的最短时间。实现会尽最大努力在超时发生后尽快检测到超时。但是,在检测到超时和线程在该超时后实际再次执行之间可能会经过不确定的时间量。所有接受超时参数的方法都将小于或等于零的值视为根本不等待。要“永远”等待,您可以使用值 Long.MAX_VALUE

同步器

五类辅助常见的特殊用途同步习惯用法。
  • Semaphore 是一个经典的并发工具。
  • CountDownLatch 是一个非常简单但非常常用的实用程序,用于阻塞直到给定数量的信号、事件或条件成立。
  • CyclicBarrier 是可重置的多路同步点,在某些风格的并行编程中很有用。
  • Phaser 提供了一种更灵活的屏障形式,可用于控制多线程之间的分阶段计算。
  • Exchanger 允许两个线程在会合点交换对象,并且在多个管道设计中很有用。

并发集合

除队列外,此包还提供专为在多线程上下文中使用而设计的集合实现:ConcurrentHashMap ConcurrentSkipListMap ConcurrentSkipListSet CopyOnWriteArrayList CopyOnWriteArraySet 。当预期许多线程访问给定集合时,ConcurrentHashMap 通常优于同步的 HashMapConcurrentSkipListMap 通常优于同步的 TreeMap。当预期的读取和遍历次数大大超过列表的更新次数时,CopyOnWriteArrayList 优于同步的 ArrayList

与此包中的某些类一起使用的“并发”前缀是一种简写,表示与类似的“同步”类的一些差异。例如 java.util.HashtableCollections.synchronizedMap(new HashMap()) 是同步的。但是 ConcurrentHashMap 是“并发”的。并发集合是线程安全的,但不受单个排他锁的约束。在 ConcurrentHashMap 的特殊情况下,它安全地允许任意数量的并发读取以及大量并发写入。当您需要通过单个锁阻止对集合的所有访问时,“同步”类会很有用,但代价是可扩展性较差。在其他需要多个线程访问公共集合的情况下,“并发”版本通常更可取。当集合未共享或仅在持有其他锁时才可访问时,非同步集合更可取。

大多数并发 Collection 实现(包括大多数队列)也不同于通常的 java.util 约定,因为它们的 迭代器Spliterators 提供 weakly consistent 而不是快速失败遍历:

  • 他们可以与其他操作同时进行
  • 他们永远不会扔 ConcurrentModificationException
  • 它们保证在构造时只遍历元素一次,并且可能(但不保证)反映构造后的任何修改。

内存一致性属性

第十七章Java 语言规范定义了发生之前内存操作的关系,例如共享变量的读取和写入。只有当写操作发生时,一个线程的写入结果才能保证对另一个线程的读取可见发生之前读取操作。 synchronizedvolatile 构造,以及 Thread.start()Thread.join() 方法,可以形成发生之前关系。尤其:
  • 线程中的每个动作发生之前该线程中的每个动作都按程序的顺序出现。
  • 监视器的解锁(synchronized块或方法退出)发生之前同一监视器的每个后续锁(synchronized 块或方法条目)。而且因为发生之前关系是可传递的,一个线程在解锁之前的所有动作发生在之前任何锁定该监视器的线程之后的所有操作。
  • 写入 volatile 字段发生之前同一字段的每次后续读取。 volatile 字段的写入和读取与进入和退出监视器具有相似的内存一致性效果,但 not 需要互斥锁定。
  • 在线程上调用 start发生之前启动线程中的任何操作。
  • 线程中的所有操作发生在之前任何其他线程从该线程上的 join 成功返回。
java.util.concurrent 及其子包中所有类的方法将这些保证扩展到更高级别的同步。尤其:
  • 将对象放入任何并发集合之前线程中的操作发生在之前在另一个线程中从集合中访问或删除该元素之后的操作。
  • 在将 Runnable 提交给 Executor 之前线程中的操作发生在之前它的执行开始。同样,Callables 提交给 ExecutorService
  • Future 表示的异步计算所采取的操作发生在之前在另一个线程中通过 Future.get() 检索结果后的操作。
  • “释放”同步器方法之前的操作,例如 Lock.unlockSemaphore.releaseCountDownLatch.countDown发生在之前在另一个线程中的同一同步器对象上成功“获取”方法(例如 Lock.lockSemaphore.acquireCondition.awaitCountDownLatch.await)之后的操作。
  • 对于通过 Exchanger 成功交换对象的每对线程,每个线程中 exchange() 之前的操作发生在之前那些在另一个线程中对应的 exchange() 之后。
  • 调用 CyclicBarrier.awaitPhaser.awaitAdvance(及其变体)之前的操作发生在之前屏障动作执行的动作,以及屏障动作执行的动作发生在之前从其他线程中相应的 await 成功返回后的操作。
Java 语言规范:
17.4.5 先于顺序发生
自从:
1.5