Reputation: 31252
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?
Upvotes: 5
Views: 9726
Reputation: 1770
Scala global
context is created with usage of Thread
factory which makes Threads
daemons, so they (threads) won’t prevent the JVM from exiting once all user threads have finished their execution.
Check ExecutionContextImpl
method def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService
.
Upvotes: 2