Jus12
Jus12

Reputation: 18024

How to use synchronized in Scala?

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

Upvotes: 37

Views: 53849

Answers (1)

Łukasz
Łukasz

Reputation: 8663

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.

Upvotes: 61

Related Questions