Tutorials Hut




  • Scala Future: Blocked calls, callbacks,  onComplete and Global Execution Context

    Future is a concept in Scala to achieve parallelism or concurrency or multi threading in Scala. As we know each and every programming language tries to process faster and run parallel multiple tasks to complete them quicker, similarly Scala has Future to run multiple small tasks in different future code blocks. In this article we will see in detail about Scala’s future and promise.

    Features and Key Points Of Scala Future

    1. Future is used to achieve parallelism in Scala.

    2. In the future each task runs independent and almost parallel.

    3. It helps in making applications faster and completing given tasks quicker.

    4. Future should be written in such a way that it should not be blocked.

    5. It helps in developing asynchronous applications.

    6. It is similar to Java’s threading.

    7. When the future or execution is not complete we call it a complete future.

    8. When the future or execution is complete we call the future is complete.

    9. Whenever we execute code in future it executes the code in thread.

    10.  Based on coding logic we may write blocking or non-blocking code.

    Syntax of Scala Future

    val inverseFuture: Future[<T Type>] = Future {
      // non-blocking long lasting computation returning some T type of data
    }(executionContext)

    Or with the more idiomatic:

    implicit val ec: ExecutionContext = ..
    val inverseFuture : Future[<T type>] = Future {
    // non-blocking long lasting computation returning some T type of data
    } // ec is implicitly passed

    Scala Future Example

    See below future example where we have written a method to do some work and return the future of String. We have used wait to block the call and resolve the future, don’t do this in production, ideally the future should not be blocked until the end of the program where it is really needed. 

    Example:

    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.duration.Duration //It is needed
    import scala.concurrent.Await
    
    object FutureInScala {
    
      def main(args: Array[String]): Unit = {
    
    	val myFutureVal: Future[String] = myFutureMethod()
    
    	println(Await.result(myFutureVal, Duration.Inf))
    
      }
      def myFutureMethod(): Future[String] = Future {
    
    	"Some long running code here, in future"
      }
    }

    Output:

    Some long running code here, in future

    Scala Execution Context, Global execution context

    To execute any future we need a ExeuctionContext, it is similar to thread pools in java, to execute threads in java we create thread pools and then inside we can have multiple threads and may run it. Similarly in Scala we have execution context, Scala by default gives such a pool which is called Global context. Note that Execution context is based on  ForkJoinPool of java.

    Global context is found in below package:

    scala.concurrent.ExecutionContext.Implicits.global.

    It is an implicit and hence once imported no need to pass it explicitly in code.

    Callbacks Using onComplete

    Callbacks are ways to call on future and find the results of future, onComplete is a call back method available in Scala future to resolve the results of future and do some processing on final data.

    Example of Callbacks using onComplete:

    Note in this example at the end we have added thread sleep method, this is just to ensure main thread does not exit before running future, don’t use such code in production. In onComplete we have two results Success or Failure, Success means future resolved and failure means something went wrong, handle the exception.

    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.util.{Failure, Success}
    object FutureInScala {
    
      def main(args: Array[String]): Unit = {
    
    	val myFutureVal: Future[String] = myFutureMethod()
    
    myFutureVal.onComplete({
      	case Success(data) => println(data)
      	case Failure(exception) => println("Failed some exception")
    	})
    
    	Thread.sleep(500) //This is to ensure main thread does not end before future, dont use in prod code
      }
      def myFutureMethod(): Future[String] = Future {
    	"Some long running code here, in future"
      } 

    Output:

    Some long running code here, in future

    Scala Blocked Call Outside Future Using Await

    In Scala there is Await class and it has methods to wait on future to specified time duration to get the results, if it is over it will give a timeout error.

    Example of Scala Await with Future:

    See println(), inside that we have used Await.result() and passed futured and Duration.Infy to wait infinite time to resolve future, we can provide custom time as well.

    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.duration.Duration //It is needed
    import scala.concurrent.Await
    
    object FutureInScala {
      def main(args: Array[String]): Unit = {
    
    	val myFutureVal: Future[String] = myFutureMethod()
    	println(Await.result(myFutureVal, Duration.Inf))
      }
      def myFutureMethod(): Future[String] = Future {
    	"Some long running code here, in future"
      }
    }

    Output:

    Some long running code here, in future

    Scala Blocked Call Inside Future Using Blocking

    We can use a blocking construct inside future to make a blocking future call, it will be blocked until execution is completed.

    Sample Code:

    implicit val ec = ExecutionContext.fromExecutor(
                    Executors.newFixedThreadPool(4))
    Future {
     blocking { blockingStuff() }
    }

    Reference

    Next Article

    • Scala Interviews

















  • Leave a Reply

    Your email address will not be published. Required fields are marked *