scala 全局 ExecutionContext 与 ExecutionContextExecutorService

scala global ExecutionContext vs ExecutionContextExecutorService

我正在使用默认全局上下文和我自己的 ExecutionContext.

玩 scala Futures

我很好奇 global context 是如何在所有执行后关闭的。因为如果我创建自己的 ExecutionContext 我必须手动关闭。

示例,

1) 使用全局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."
    }
  }
}

输出

$ 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

执行完成后,应用终止。

2) 使用自己的 ExecutionContext - 应用程序在所有执行完成后不会终止,直到我手动 .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."
    }
  }
}

输出

$ 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>

这是 JVisualVM 线程监视器,

我的问题是 scala 的全局上下文如何在不询问客户端的情况下自动终止?

Scala global 上下文是使用 Thread 工厂创建的,它使 Threads 守护进程,所以它们(线程)不会阻止 JVM 在所有用户线程退出后退出完成了他们的执行。

检查ExecutionContextImpl方法def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService