线程提供了一种表达并发的方式:它们给你独立的,堆共享的(heap-sharing)由操作系统调度的执行上下文。然而,在Java里线程的创建是昂贵的,是一种必须托管的资源,通常借助于线程池。这对程序员创造了额外的复杂,也造成高度的耦合:很难从所使用的基础资源中分离应用逻辑。

    当创建高度分散(fan-out)的服务时这种复杂度尤其明显: 每个输入请求导致一大批对另一层系统的请求。在这些系统中,线程池必须被托管以便根据每一层请求的比例来平衡:一个线程池的管理不善会导致另一个线程池也出现问题。

    一个健壮系统必须考虑超时和取消,两者都需要引入更多“控制”线程,使问题更加复杂。注意若线程很廉价这些问题也将会被削弱:不再需要一个线程池,超时的线程将被丢弃,不再需要额外的资源管理。

    使用Future管理并发。它们将并发操作从资源管理里解耦出来:例如,Finagle(译注:twitter的一个RFC框架)以有效的方式在少量线程上实现并发操作的复用。Scala有一个轻量级的闭包字面语法(literal syntax),所以Futures引入了很少的语法开销,它们成为很多程序员的第二本能。

    Futures允许程序员用一种可扩充的,有处理失败原则的声明风格,来表达并发计算。这些特性使我们相信它们尤其适合在函数式编程中用,这也是鼓励使用的风格。

    更愿意转换(transforming)future而非自己创造。Future的转换(transformations)确保失败会传播,可以通过信号取消,对于程序员来说不必考虑Java内存模型的含义。甚至一个仔细的程序员会写出下面的代码,顺序地发出10次RPC请求而后打印结果:

    1. if (results.length < 9)
    2. else
    3. collect() onSuccess { results =>
    4. }

    我们用flatMap顺序化操作,把我们处理中的结果预追加(prepend)到list中。这是一个通用的函数式编程习语的Futures译本。这是正确的,不仅需要的样板代码(boilerplate)可以减少,易出错的可能性也会减少,并且读起来更好。

    Future组合子(combinators)的使用。当操作多个futures时,Future.select,Future.join和Future.collect应该被组合编写出通用模式。

    集合

    并发集合的主题充满着意见、微妙(subtleties)、教条、恐惧/不确定/怀疑(FUD)。在大多实际场景都不存在问题:总是先用最简单,最无聊,最标准的集合解决问题。 在你知道不能使用synchronized前不要去用一个并发集合:JVM有着老练的手段来使得同步开销更小,所以它的效率能让你惊讶。

    可变的并发集合有着复杂的语义,并利用Java内存模型的微妙的一面,所以在你使用前确定你理解它的含义——尤其对于发布更新(新的公开方法)。同步的集合同样写起来更好:像getOrElseUpdate操作不能够被并发集合正确的实现,创建复合(composite)集合尤其容易出错。