I'm playing with scala Futures with default global context and my own ExecutionContext
.
I'm curious how global context
is shutdown after all executions. Because if I create my own ExecutionContext
I have to manually shutdown.
Example,
1) Using global executionContext,
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
object ParallelTasksWithGlobalExecutionContext {
private val data: Iterable[Input] = Iterable("data1", "data2", "data3")
def main(args: Array[String]): Unit = {
val f: Future[Unit] = Future.traverse(data) { d =>
println(s"[${Thread.currentThread().getName}]-Firing $d")
processData(d)
} map { processed =>
processed.foreach(p => println(s"""[${Thread.currentThread().getName}]-$p"""))
}
Await.result(f, Duration.Inf)
}
type Input = String
type Output = String
def processData: (Input => Future[Output]) = data => {
Future {
Thread.sleep(5000)
s"[Thread-${Thread.currentThread().getName}] data $data is processed."
}
}
}
Output
$ sbt "runMain ParallelTasksWithGlobalExecutionContext"
[info] Running ParallelTasksWithGlobalExecutionContext
[run-main-0]-Firing data1
[run-main-0]-Firing data2
[run-main-0]-Firing data3
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-58] data data1 is processed.
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-59] data data2 is processed.
[scala-execution-context-global-59]-[Thread-scala-execution-context-global-60] data data3 is processed.
[success] Total time: 6 s, completed Apr 1, 2018 12:44:36 AM
After the execution is completed, application is terminated.
2) Using own ExecutionContext - the application does not terminate after all executions are done until I manually .shutdown
.
import java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService, Future}
import scala.util.{Failure, Success}
object ParallelTasksWithCustomExecutionContext {
private val data: Iterable[Input] = Iterable("data1", "data2", "data3")
implicit val singleThreadContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(3))
def main(args: Array[String]): Unit = {
Future.traverse(data) { d =>
println(s"[${Thread.currentThread().getName}]-Firing $d")
processData(d)
} onComplete {
case Success(processed) =>
processed.foreach(p => println(s"""[${Thread.currentThread().getName}]-$p"""))
//singleThreadContext.shutdown()
case Failure(f) =>
f.printStackTrace()
//singleThreadContext.shutdown()
}
}
type Input = String
type Output = String
def processData: (Input => Future[Output]) = data => {
Future {
Thread.sleep(5000)
s"[Thread-${Thread.currentThread().getName}] data $data is processed."
}
}
}
Output
$ sbt "runMain ParallelTasksWithCustomExecutionContext"
[info] Running ParallelTasksWithCustomExecutionContext
[run-main-0]-Firing data1
[run-main-0]-Firing data2
[run-main-0]-Firing data3
[pool-7-thread-1]-[Thread-pool-7-thread-1] data data1 is processed.
[pool-7-thread-1]-[Thread-pool-7-thread-2] data data2 is processed.
[pool-7-thread-1]-[Thread-pool-7-thread-3] data data3 is processed.
<hangs>
And this is JVisualVM Thread monitor,
My question is how scala's global context terminates automatically without asking the client?