2013-06-20 8 views
20

Я использую Play Framework 2.1.1 с внешней java-библиотекой, которая создает java.util.concurrent.Future результат. Я использую будущее scala, а не Akka, которое, я думаю, правильно, как в Play 2.1. Как я могу обернуть java.util.concurrent.Future в файл scala.concurrent.Future, сохраняя при этом код без блокировки?scala.concurrent.Future обертка для java.util.concurrent.Future

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

Приведенный выше код возвращает соединение, но использует получить так, что становится блокирующим

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

В идеале я хочу функцию SCALA, которая возвращает соединение в качестве будущего как код выше, но без кода блокировки через get. Что еще мне нужно, чтобы включить функцию, чтобы она не блокировалась.

Любые указатели были бы замечательными.

+0

Какую версию Scala вы используете? Начиная с 2.10.x, Scala приняла «Будущее Акки» как свое собственное. –

+0

Play 2.1.1 использует Scala 2.10.0 под обложками –

ответ

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

Вы не можете обернуть JFuture с SFuture без блокировки, так как существует обратный вызов в SFuture (onComplete) и есть только блокирующие get в JFuture.

Все, что вы можете сделать, это создать дополнительную нить и заблокировать ее с помощью get, а затем заполнить Promise с результатом 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 

Вы можете проверить isDone в бесконечном цикле, но я не думаю, что это лучше, чем блокирование.

+2

Согласен. Весь стыд в том, что будущее Java не поддерживает какой-либо прослушиватель/наблюдатель завершения для обратного вызова – cmbaxter

+0

@cmbaxter, если вы используете Guava, есть 'ListenableFuture' – fge

+0

Итак, я думал о линиях обратного вызова для java peice, что когда законченный, имел бы результат в будущем scala. Оглядываясь, есть примеры обратных вызовов, реализованных на Java (http://technology.amis.nl/2009/02/19/asynchronous-processing-in-java-applications-leveraging-those-multi-cores/), но не были конечно, как перевернуть это в Play 2.1. Оптимистично я надеялся на простую оболочку, но это не выглядит выполнимым, и обратный вызов java внутри функции scala выглядит следующим образом. –

2
Future { 
    blocking { 
    jfuture.get 
    } 
} 

Это позволяет ExecutionContext знать, что вы делаете, будет блокировать, давая ему возможность выделять больше потоков. Если вы не указали blocking { }, тогда у вас может закончиться поток.

+0

Возможно, вы захотите предоставить подробную информацию о том, что это за плюсы и минусы. Это то же самое, что обсуждалось выше (в комментариях, например, от @senia) – akauppi

+1

Прошу прощения. Добавлен комментарий, чтобы объяснить использование «блокировки». –

+1

И если вы делаете «блокировку», вы можете получить десятки тысяч потоков при высокой нагрузке. Будьте осторожны - «блокировка» не волшебство! – folex

0

Библиотека scala-java8-compat предоставляет преобразователи между java8 и Scala Futures.

В частности, вы можете использовать FutureConverters.toScala(connectionPool.getConnectionAsync()) для преобразования java.util.concurrent.Future в scala.concurrent.Future

+0

Этот ответ вводит в заблуждение. scala-java8-compat позволяет конвертировать из 'java.util.concurrent.CompletionStage' в' scala.concurrent.Future'. Не существует «правильного» способа преобразования Java Future в будущее Scala. – fcs

1
 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 

    }