This is the fourth of several posts describing protips for scala.concurrent.Future
.
For the previous post, click here.
BlockContexts
A rather well-known problem is the use of thread blocking
—pausing the execution of a Thread
, usually until some sort of condition is met, either a period of time (Ex. Thread.sleep(millis)
), or some kind of external trigger (Ex. the completion of an IO operation). The consequence of blocking is that the blocked thread cannot perform any work, not even unrelated work, while being blocked.
In order to ameliorate the impact of blocking SIP-14 introduced the concept of a BlockContext
, which can perform actions in response to the signalling of a blocking execution, with the downside that the piece of blocking code needs to be surrounded in a blocking {}
-block1 like so:
import scala.concurrent._
def foo() = blocking {
println("foo")
}
scala>foo()
foo
Let’s say that we want to prohibit blocking within a certain scope, then we could define the following BlockContext
:
import scala.concurrent._
import java.security.AccessControlException
object NoBlock extends BlockContext {
def blockOn[T](thunk: => T)(implicit permission: CanAwait): T =
throw new AccessControlException("Permission to block DENIED")
}
And then we could install that BlockContext
in a specific call chain as so:
scala>foo()
foo
scala> BlockContext.withBlockContext(NoBlock) { foo() }
java.security.AccessControlException: Permission to block DENIED
at NoBlock$.blockOn(<console>:20)
at scala.concurrent.package$.blocking(package.scala:142)
at .foo(<console>:19)
at .$anonfun$res3$1(<console>:21)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
... 29 elided
Mission accomplished!
Cheers,
√
Click here for the next part in this blog series.
-
Both
Await.result
andAwait.ready
do this under the hood. ↩