您的代码正常工作的原因是两个期货将由同一个线程执行。您正在创建的ExecutionContext不会Thread直接为每个使用,Future而是会安排Runnable要执行的任务(实例)。如果池中没有更多线程可用,这些任务将被置于BlockingQueue等待执行的状态。(详见ThreadPoolExecutor API)
如果您查看实现,Executors.newFixedThreadPool(1)您会发现它创建了一个具有无界队列的 Executor:
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue[Runnable])
要获得您正在寻找的线程饥饿的效果,您可以自己创建一个具有有限队列的执行程序:
implicit val ec = ExecutionContext.fromExecutor(new ThreadPoolExecutor(1, 1, 0L,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue[Runnable](1)))
由于 的最小容量ArrayBlockingQueue为 1,您需要三个期货才能达到限制,并且您还需要添加一些代码以在未来的结果上执行,以防止它们完成(在下面的示例中,我这样做是通过添加.map(identity))
下面的例子
import scala.concurrent._
implicit val ec = ExecutionContext.fromExecutor(new ThreadPoolExecutor(1, 1, 0L,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue[Runnable](1)))
def addOne(x: Int) = Future {
x + 1
}
def addTwo(x: Int) = Future {
addOne(x + 1) .map(identity)
}
def addThree(x: Int) = Future {
addTwo(x + 1).map(identity)
}
println(addThree(1))
失败了
java.util.concurrent.RejectedExecutionException: Task scala.concurrent.impl.CallbackRunnable@65a264b6 rejected from java.util.concurrent.ThreadPoolExecutor@10d078f4[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 1]