scala.concurrent.Future wrapper for java.util.concurrent.Future
Asked Answered
S

4

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.

Stamen answered 20/6, 2013 at 13:51 Comment(2)
Which version of Scala are you using? As of 2.10.x, Scala adopted Akka's Future as its own.Speculative
Play 2.1.1 uses Scala 2.10.0 under the coversStamen
P
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.

Pep answered 20/6, 2013 at 14:1 Comment(6)
Agreed. Total shame that the Java future does not support some sort of completion listener/observer for a callbackLeaden
@Leaden if you use Guava, there is ListenableFuturePulmonate
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 (technology.amis.nl/2009/02/19/…) 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.Stamen
I'm curious, what's wrong with future { jfuture.get }? Why you used an extra thread combined with Promise?Congruity
@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 threads as you have processors.Pep
@senia, I have opened a question about why future { jfuture.get } is not enough.Sandy
C
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.

Chartulary answered 25/2, 2016 at 19:13 Comment(3)
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)Stymie
Sorry about that. Added a comment to explain the use of "blocking".Chartulary
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!Shadchan
Y
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

     }
Yearly answered 20/6, 2013 at 13:51 Comment(2)
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); }Kinswoman
Yes, It will block executing thread but not calling thread. That's intention not block calling thread.Yearly
P
-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

Precontract answered 9/9, 2017 at 20:4 Comment(1)
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.Mikkel

© 2022 - 2024 — McMap. All rights reserved.