33

I have the following code:

object Foo {
 private var ctr = 0L

 def bar = {
   ctr = ctr + 1
   // do something with ctr
 }
}

The requirement is that a ctr value should be used only once. In my case the same value of ctr is getting reused. My theory is that this happens because Foo.bar is called concurrently in different threads (this is the only conclusion I could draw). I have the following modified code as a fix.

object Foo {
 private var ctr = 0L
 def getCtr = synchronized{
   ctr = ctr + 1
   ctr
 }
 def bar = {
   val currCtr = getCtr
   // do something with currCtr
 }
}

I could not find a good guide for using the synchronized method in Scala. Can anyone let me know if the above code will fix my problem.

EDIT: Based on the comments below, I think AtomicLong is the best solution for me:

import java.util.concurrent.atomic.AtomicLong
private val ctr = new AtomicLong
def getCtr = ctr.incrementAndGet
Jus12
  • 17,058
  • 25
  • 90
  • 151
  • 1
    Have you had a look at this already https://twitter.github.io/scala_school/concurrency.html ? You could also use an AtomicLong. – Markon Jan 19 '16 at 13:03
  • 2
    I'd side-step the issue and use an `AtomicInteger`. Those are made for concurrent counters. – Thilo Jan 19 '16 at 13:08
  • 4
    +1. I understand emphasis on higher-level concurrency (futures, actors, etc), but it's a pity definitive Scala books don't even _mention_ `obj.synchronized` syntax. – Victor Sorokin Jan 19 '16 at 13:30

1 Answers1

51

If you don't want an AtomicInteger, here is how to use synchronized

object Foo {
 private var ctr = 0L
 def getCtr = this.synchronized {
   ctr = ctr + 1
   ctr
 }
 def bar = {
    val currCtr = getCtr
    // do something with currCtr
  }
}

You need to synchronize on some object. In this case on your current object which is this.

In short: Scala's format is (and the block can return a value)

this.synchronized {
   ctr = ctr + 1
   ctr
}

It is equivalent of java's

synchronized(this) {
   return ++ctr;   
}

Scala does not have synchronized methods as java, just blocks.

Edit

To answer the question from comment below: synchronized can be used as a method from class AnyRef:

https://www.scala-lang.org/api/current/scala/AnyRef.html

final def synchronized[T0](arg0: ⇒ T0): T0

so you are calling a method of your object, just like you would do toString and this.toString.

arberg
  • 3,672
  • 4
  • 24
  • 29
Łukasz
  • 8,224
  • 2
  • 24
  • 48
  • 4
    What happens if I skip `this`? The code does compile and seems to behave correctly. – Jus12 Jan 19 '16 at 16:40
  • 3
    Note that unlike `toString` it isn't _actually_ a method on `AnyRef`, the compiler just pretends it is. – Alexey Romanov Jan 19 '16 at 19:20
  • 2
    Within an `object`, is `this.synchronized {...}` the same as `synchronized {...}`? – Jus12 Jan 20 '16 at 03:04
  • @Łukasz out of the two, `AtomicLong` or `synchronized`, which one is preferred? – Jus12 Jan 20 '16 at 03:08
  • 1
    Yes, it is the same as it works as a method. If you had class `A { def a = 3; def b = a; def c = this.a }` `b` and `c` would do the same. In general it is perfered not to use things like `synchronized`, `wait`, `notify` as they are low level and error prone. `AtomicLong` is also faster. You can read about synchronized vs atomics here: http://stackoverflow.com/questions/9749746/what-is-the-difference-of-atomic-volatile-synchronize – Łukasz Jan 20 '16 at 09:06
  • "It isn't actually a method on AnyRef, the compiler just pretends it is." That's pretty much the story of Scala right there. – einnocent May 03 '17 at 23:09
  • I know it is a nit, but shouldn't that be `synchronized(this) { return ++ctr }` since the original code did a pre-increment, not a post-increment? – Jesse Chisholm Oct 10 '19 at 15:50
  • @JesseChisholm You are right :) Thanks, I edited the answer. – Łukasz Oct 11 '19 at 17:27