Visibility of var among threads


#1

I’m reading Learning Concurrent Programming in Scala - Second Edition (https://www.packtpub.com/application-development/learning-concurrent-programming-scala-second-edition) and wanted to know…

Is count guaranteed to have the correct value in each loop below? If so, why?

object AtomicLock extends App {
  import java.util.concurrent.atomic._
  private val lock = new AtomicBoolean(false)
  def mySynchronized(body: =>Unit): Unit = {
    while (!lock.compareAndSet(false, true)) {}
    try body
    finally lock.set(false)
  }

  var count = 0
  for (i <- 0 until 10) execute {
    mySynchronized { count += 1 }
  }
  Thread.sleep(1000)
  log(s"Count is: $count")
}

execute is defined:

def execute(body: =>Unit) = ExecutionContext.global.execute(new Runnable {
    def run() = body
})

I can see that body's execution is atomic, but I don’t see what makes count's value guaranteed visible in whatever thread is currently being used for each loop.


#2

While writing another question, Does a write to a volatile var make previous writes visible?, it occurred to me if that question holds up, then I may have the answer.

Perhaps finally lock.set(false) makes the value of count visible because of the write to the AtomicBoolean, which behaves like to write to a volatile for visibility purposes as described in other question?


#3

The computing threads are fine because they read the atomic Boolean before they read count (and write count before they write the atomic Boolean). What doesn’t work in this program is the final log statement, which reads count directly. There’s no guarantee to see an up-to-date value at this point.

This code is terrible (and the code in your other question is even worse). They are not examples from the book, are they?


#4

Good point about the log statement.

The scripts are from the book. While I’m in no position to defend these scripts, I will say the book doesn’t present them as best practice. These are in the early chapters just to get a general understanding of some of the lower level constructs before moving on to higher level scala specific concurrency options, which is what the book is really about.


#5

Understood. The other code is worse because of busy-waiting and of races in page changes while the main thread is checking them. I think it’s better to start with more basic concepts and discuss the JMM later, using clean code. But it can be tricky (the JCIP book keeps it for the end, but some do’s and don’ts in the earlier chapters can see a bit arbitrary until then).


#6

You’re probably right - I may not have had these questions with a clearer approach. I’m still looking forward to the scala specific stuff, but I’ll keep the JCIP book in mind if I’m still unsure. Thanks for the input :slight_smile: