Run two computations in parallel, and return the results together I am reading the "Learning Concurrent Programming in Scala" and there are exercises in the end of each chapter.
One of exercises is


  Implement a parallel method which takes two computation blocks a and
  b, and starts each of them in a new thread. The method must return a
  tuple with the result values of both the computations. It should have
  the following signature: def parallel[A, B](a: => A, b: => B):(A, B)


I have implemented it in this way:

def parallel[A, B](a: =&gt; A, b: =&gt; B):(A, B) = {
  var aResult:Option[A] = Option.empty
  var bResult:Option[B] = Option.empty
  val t1 = thread{aResult = Some(a)}
  val t2 = thread{bResult = Some(b)}
  t1.join()
  t2.join()
  (aResult.get, bResult.get)
}


where thread is

def thread(block: =&gt;Unit):Thread = {
  val t = new Thread{
    override def run(): Unit = block
  }
  t.start()
  t
}


My question is if this implementation is free of race condition? I have seen that other people had a similar implementations but declared result holder variables aResult and bResult to be volatile. I am not sure that this is necessary, and also I was not able to design a test which would break the correctness of my implementation.

From my point of view the implementation is free of race condition because the parallel method does not access any shared variables. All its state is in its local variables so is not shared. Thus I think that adding @volatile to aResult and bResult is not needed in this case.
From my point of view the implementation is free of race condition because the parallel method does not access any shared variables. All its state is in its local variables so is not shared. 


That is not true. The variable aResult is shared between the thread that called parallel and the thread t1. So there needs to be some synchronization between these two threads, otherwise you run into undefined behaviour.



This low-level JDK memory model gets tricky, so I would try to avoid it as far as possible, i.e. use higher-level abstractions and prefer immutable state.

I suppose the following (still rather low-level) tools (which would solve these issues) are not available for this exercise:


Scala Futures
Java Callables (which return a result instead of having to publish it somewhere)
java.util.concurrent.AtomicReference (which you can use as a thread-safe holder if you have to use Runnable instead of Callable)




As for the specific question: According to the Java Memory Model FAQ


  All actions in a thread happen before any other thread successfully returns from a join() on that thread.


Meaning that after your master thread has joined the first worker thread, it will read the updated value of aResult without that field needing to be volatile.

So your code looks correct to me.

But I had to look this up. Really try to avoid mutable state when multiple threads are concerned.