scala future timeout strange behaviour

Viewed 205

Here is example code scala 2.13.3:

import scala.concurrent.{ExecutionContext}

val scheduller: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()

val promise = Promise[A]()
scheduller.schedule(
  new Runnable {
    override def run(): Unit = {
      promise.failure(new TimeoutException)
      scheduller.shutdown()
    }
  },
  500,
  TimeUnit.MILLISECONDS
)
Future.firstCompletedOf(Seq(INF_FUTURE, promise.future))

the time out will work if INF_FUTURE = Future.never but execution will not stops if INF_FUTURE = Future {while (true) {}} Can you explane what is going on here?

1 Answers

It is because you use singleThreadScheduledExecutor. I assume you creates ExecutionContext from scheduller:

val scheduller: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
implicit val ec: ExecutionContextExecutor = scala.concurrent.ExecutionContext.fromExecutorService(scheduller)

val promise = Promise[Int]()
scheduller.schedule(
  new Runnable {
    override def run(): Unit = {
      promise.failure(new TimeoutException)
      scheduller.shutdown()
    }
  },
  500,
  TimeUnit.MILLISECONDS
)

If you create execution context only with one executor your program will evaluate synchronous and freeze inside while (true) loop.

If you will switch to global Execution context the problem will be missed (if your machine has more then one core):

implicit val ec: ExecutionContextExecutor = scala.concurrent.ExecutionContext.global

in case of Future.never if you will wait for result like so:

Await.result(Future.firstCompletedOf(Seq(INF_FUTURE, promise.future)).map {
  x =>
    println(x)
}, 10.seconds)

you will get Exception:

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@eb88a9df rejected from java.util.concurrent.ScheduledThreadPoolExecutor@e24c7ced[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 1]

which call you about problem with thread pool size. So, you don't have any problem with Future.never because you didn't wait for it's result.

Related