Reputation: 23633
In Scala, as far as I can tell, ExecutionContext.global
is different from other ExecutionContext
objects one might typically create using ExecutionContext.fromExecutor(...)
because it can use scala.concurrent.blocking
as a signal to spawn additional threads when an initially small thread pool becomes blocked with long-running, possibly io-bound computation. Is there a way to create another such ExecutionContext
? Looking at the source code, it appears that ExecutionContext.global
is created in a fairly unique way, through an internal call to impl.ExecutionContextImpl.fromExecutor(null: Executor)
, which is package-private.
Upvotes: 2
Views: 473
Reputation: 13959
So you can create this pretty easily with this:
scala.concurrent.ExecutionContext.fromExecutor(null)
It will go through the exact same process as ExecutionContext.global
.
Behind the scenes this is just creating a ForkJoinPool
with a special ThreadFactory
for handling scala.concurrent.blocking
signals. If you want more control you can just create your own ForkJoinPool
and then provide a ThreadFactory
doing something similar to what the scala version does(source) :
class DefaultThreadFactory(daemonic: Boolean) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory {
def wire[T <: Thread](thread: T): T = {
thread.setDaemon(daemonic)
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler)
thread
}
def newThread(runnable: Runnable): Thread = wire(new Thread(runnable))
def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = wire(new ForkJoinWorkerThread(fjp) with BlockContext {
override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = {
var result: T = null.asInstanceOf[T]
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker {
@volatile var isdone = false
override def block(): Boolean = {
result = try thunk finally { isdone = true }
true
}
override def isReleasable = isdone
})
result
}
})
}
Additionally, Akka has an implimentation as well for its FJP
.
Upvotes: 1