23

I'm using Play Framework 2.1.1 with an external java library that produces a java.util.concurrent.Future result. I'm using the scala future's as opposed to Akka which I think is the right thing to do as of Play 2.1. How can I wrap the java.util.concurrent.Future up into a scala.concurrent.Future while still keeping the code non-blocking?

def geConnection() : Connection = {
  // blocking with get
  connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS)
}

The above code returns a connection but uses a get so it becomes blocking

def getConnectionFuture() : Future[Connection] = {
  future {
    // how to remove blocking get and return a scala future?
    connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS)
  }
}

Ideally I want a scala function that returns the connection as a future like the code above but without the code blocking via the get. What else do I need to put into the function to make it non blocking.

Any pointers would be great.

Mark Sivill
  • 825
  • 1
  • 9
  • 18

4 Answers4

21
import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{Future => SFuture}

You can't wrap JFuture with SFuture without blocking since there is a callback in SFuture (onComplete) and there is only blocking get in JFuture.

All you can do is to create additional thread and block it with get, then complete Promise with result of get.

val jfuture: JFuture[T] = ???
val promise = Promise[T]()
new Thread(new Runnable { def run() { promise.complete(Try{ jfuture.get }) }}).start
val future = promise.future

You could check isDone in endless loop, but I don't think it is better then blocking.

senia
  • 37,745
  • 4
  • 88
  • 129
  • 3
    Agreed. Total shame that the Java future does not support some sort of completion listener/observer for a callback – cmbaxter Jun 20 '13 at 14:06
  • @cmbaxter if you use Guava, there is `ListenableFuture` – fge Jun 20 '13 at 14:11
  • So I was thinking along the lines of a callback for the java peice, that when finished, would have its result up in scala future. Looking around there are examples of callbacks implemented in Java (http://technology.amis.nl/2009/02/19/asynchronous-processing-in-java-applications-leveraging-those-multi-cores/) but wasn't sure how to roll this into Play 2.1. Optimistically I was hoping for a simple wrapper but it doesn't look thats doable, and a java callback within a scala function looks the way to go. – Mark Sivill Jun 20 '13 at 15:07
  • I'm curious, what's wrong with `future { jfuture.get }`? Why you used an extra thread combined with `Promise`? – Petr Jun 20 '13 at 16:04
  • 4
    @PetrPudlák: it'll block thread in your thread pull. If you have a configured `ExecutionContext` for such futures it's fine, but default `ExecutionContext` contains [as many](https://github.com/scala/scala/blob/v2.10.2/src/library/scala/concurrent/impl/ExecutionContextImpl.scala#L68) threads as you have processors. – senia Jun 20 '13 at 16:42
  • 1
    @senia, I have opened a [question](http://stackoverflow.com/q/21190140/1714997) about why `future { jfuture.get }` is not enough. – Dominykas Mostauskis Jan 17 '14 at 16:02
7
Future {
  blocking {
    jfuture.get
  }
}

This lets the ExecutionContext know that what you are doing is going to block, giving it a chance to allocate more threads. If you do not include blocking { } then you may run out of threads.

Dr.Haribo
  • 1,778
  • 1
  • 31
  • 43
  • You might want to provide details on what the pros/cons of this are. Is it the exact same as discussed above (in comments e.g. from @senia) – akauppi Mar 06 '16 at 10:33
  • 1
    Sorry about that. Added a comment to explain the use of "blocking". – Dr.Haribo Mar 07 '16 at 19:10
  • 3
    And if you do 'blocking' then you could end up with tens of thousands of threads on high load. Be careful -- 'blocking' is no magic! – folex May 27 '16 at 10:23
2
     import java.util.concurrent.{Future => JFuture}
     import scala.concurrent.ExecutionContext.Implicits.global
     import scala.concurrent.Future
     import scala.util.Try

     object JFuture2SFuture {
        val jFuture: JFuture[Int] = ???
        val promise = Promise[Int]()
        Future { promise.complete(Try(jFuture.get)) } //it is non blocking 
        val sFuture:Future[Int] = promise.future

     }
Sky
  • 2,509
  • 1
  • 19
  • 28
  • 1
    The comment says 'it is non-blocking' but this looks like it would block the executing thread to me. `Try.apply` is a by-name call but that doesn't imply it would execute asynchronously. Promise.complete is similarly blocking. This does wrap the java future's `.get`. in an async scala `Future`, but it would still block the executing thread, similar to `Future { Thread.sleep(10000); }` – drobert Apr 09 '18 at 15:28
  • Yes, It will block executing thread but not calling thread. That's intention not block calling thread. – Sky Apr 11 '18 at 05:37
-1

The scala-java8-compat library provides converters between java8 and Scala Futures.

Specifically, you can use FutureConverters.toScala(connectionPool.getConnectionAsync()) to convert the java.util.concurrent.Future to scala.concurrent.Future

Arnout Engelen
  • 6,709
  • 1
  • 25
  • 36
Sumit
  • 2,189
  • 7
  • 32
  • 50
  • 2
    This answer is misleading. scala-java8-compat enables converting from `java.util.concurrent.CompletionStage` to `scala.concurrent.Future`. There is no "proper" way to convert a Java Future to Scala Future. – fcs Sep 22 '17 at 12:34