Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why new thread instead of future {...}

This answer instructs how to convert java.util.concurrent.Future into scala.concurrent.Future, while managing where the blocking will occur:

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

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

My queston is the same as a question asked in the comments:

what's wrong with future { jfuture.get }? Why you used an extra thread combined with Promise?

It was answered as follows:

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.

I'm not sure I understand the explanation. To reiterate:

What's wrong with future { jfuture.get }? Isn't blocking inside a future the same as manually creating a new Thread and blocking there? If not, how is it different?

like image 970
Dominykas Mostauskis Avatar asked Jan 17 '14 15:01

Dominykas Mostauskis


People also ask

Does Future create a new thread?

If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache.

What is thread and a Future?

A Java Thread represents a thread of execution in an Java/Scala/JVM application. You can run code in parallel in a Thread , but a Thread does not have a return type. A Scala Future represents the result of an asynchronous computation, and has a return type.

Which is the correct way to start a new thread?

The easiest way to create a thread is to create a class that implements the Runnable interface. To execute the run() method by a thread, pass an instance of MyClass to a Thread in its constructor (A constructor in Java is a block of code similar to a method that's called when an instance of an object is created).

What is the difference between a Java Future and a Scala Future?

A Java Future works in a synchronous blocking way. It does not work in an asynchronous non-blocking way, whereas a Scala Future works in an asynchronous non-blocking way. If we want an asynchronous non-blocking feature, we should use Java 8's CompletableFuture.


2 Answers

There is almost no difference between future { jfuture.get } and future { future { jfuture.get }}.

There are as many treads in default thread pool as many you have processors.

With jfuture.get you'll get 1 thread blocked.

Let's assume you have 8 processors. Also let's suppose each jfuture.get takes 10 seconds. Now create 8 future { jfuture.get }.

val format = new java.text.SimpleDateFormat("HH:mm:ss").format(_: Date)

val startTime = new Date
(1 to 8) map {_ => future{ Thread.sleep(10000) }}
future{
  2+2
  println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}

// 2+2 done. Start time: 20:48:18, end time: 20:48:28

10 seconds is a little too long for 2+2 evaluation.

All other futures and all actors on the same execution context will be stopped for 10 seconds.

With additional execution context:

object BlockingExecution {
  val executor = ExecutionContext.fromExecutor(new ForkJoinPool(20))
}

def blockingFuture[T](f: => T) = {
  future( f )(BlockingExecution.executor)
}

val startTime = new Date
(1 to 8) map {_ => blockingFuture{ Thread.sleep(10000) }}
future{
  2+2
  println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}

// 2+2 done. Start time: 21:26:18, end time: 21:26:18

You could implement blockingFuture using new Thread(new Runnable {..., but additional execution context allows you to limit threads count.

like image 133
senia Avatar answered Nov 15 '22 16:11

senia


It's actually quite simple. scala.concurrent.Promise is a concrete implementation of a Future, destined to be an asynchronous computation.

When you want to convert, with jfuture.get, you are running a blocking computation and outputting an immediately resolved scala.concurrent.Future.

The Thread will block until the computation inside jfuture is complete. The get method is blocking.

Blocking means nothing else will happen inside that Thread until the computation is complete. You are essentially monopolising the Thread with something that looks like a while loop intermittently checking for results.

while (!isDone() && !timeout) {
   // check if the computation is complete
}

Specifically:

val jfuture: JFuture[T] = ??? // some blocking task

When blocking cannot be avoided, the common practice is to spawn a new Thread and a new Runnable or new Callable to allow the computation to execute/monopolize a child thread.

In the example @senia gave:

new Thread(new Runnable { def run() {
  promise.complete(Try{ jfuture.get })
}}).start

How is this different than future {jfuture.get}? It doesn't block your default ExecutionContext, provided by Scala, which has as many threads as the processors of the machine.

That would mean all other futures in your code will always have to wait for future { jfuture.get } to complete, since the entire context is blocked.

like image 31
flavian Avatar answered Nov 15 '22 18:11

flavian