Protect a shared counter update with a synchronized block.

synchronized A synchronized block lets only one thread update the shared value at a time, keeping the final count predictable.

Synchronized Counter

amount
SynchronizedCounter.scala
Replay: real traced execution (multi-file project)
object Main {
  val lock = new Object()
  var counter = 0

  def add(amount: Int): Unit = {
    lock.synchronized {
      counter = counter + amount
    }
  }

  def main(args: Array[String]): Unit = {
    val amount = 2

    val first = Thread(() => add(amount))
    val second = Thread(() => add(amount + 1))

    first.start()
    second.start()
    first.join()
    second.join()

    println("amount=" + amount)
    println("counter=" + counter)
  }
}
object Main {
  val lock = new Object()
  var counter = 0

  def add(amount: Int): Unit = {
    lock.synchronized {
      counter = counter + amount
    }
  }

  def main(args: Array[String]): Unit = {
    val amount = 1

    val first = Thread(() => add(amount))
    val second = Thread(() => add(amount + 1))

    first.start()
    second.start()
    first.join()
    second.join()

    println("amount=" + amount)
    println("counter=" + counter)
  }
}
object Main {
  val lock = new Object()
  var counter = 0

  def add(amount: Int): Unit = {
    lock.synchronized {
      counter = counter + amount
    }
  }

  def main(args: Array[String]): Unit = {
    val amount = 4

    val first = Thread(() => add(amount))
    val second = Thread(() => add(amount + 1))

    first.start()
    second.start()
    first.join()
    second.join()

    println("amount=" + amount)
    println("counter=" + counter)
  }
}
  1. amount ← 2, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    11def main(args: Array[String]): Unit = {12  val amount→ 2 = 2 //@amount=1, 41314  val first→ Thread[#19,Thread-0,5,main] = Thread(() => add(amount))15  val second→ Thread[#20,Thread-1,5,main] = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  second.start()19  first.join()
  2. def add(amount: Int): Unit =

    pass 1 of 2
    5def add(amount2: Int): Unit = {6  lock.synchronized {
  3. first.start()

    5def add(amount: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter0 + amount28  }9}1011def main(args: Array[String]): Unit = {12  val amount = 2 //@amount=1, 41314  val first = Thread(() => add(amount))15  val second = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  secondThread[#20,Thread-1,5,main].start()19  first.join()20  second.join()
  4. def add(amount: Int): Unit =

    pass 2 of 2
    5def add(amount3: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter2 + amount38  }9}
  5. second ← Thread[#20,Thread-1,5,]

    17    first.start()18    second→ Thread[#20,Thread-1,5,].start()19    firstThread[#19,Thread-0,5,].join()20    secondThread[#20,Thread-1,5,].join()2122    println("amount=" + amount2)23    println("counter=" + counter5)24  }25}
    outputamount=2
    counter=5
  1. amount ← 1, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    11def main(args: Array[String]): Unit = {12  val amount→ 1 = 11314  val first→ Thread[#19,Thread-0,5,main] = Thread(() => add(amount))15  val second→ Thread[#20,Thread-1,5,main] = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  second.start()19  first.join()
  2. def add(amount: Int): Unit =

    pass 1 of 2
    5def add(amount1: Int): Unit = {6  lock.synchronized {
  3. first.start()

    5def add(amount: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter0 + amount18  }9}1011def main(args: Array[String]): Unit = {12  val amount = 11314  val first = Thread(() => add(amount))15  val second = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  secondThread[#20,Thread-1,5,main].start()19  first.join()20  second.join()
  4. def add(amount: Int): Unit =

    pass 2 of 2
    5def add(amount2: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter1 + amount28  }9}
  5. second ← Thread[#20,Thread-1,5,]

    17    first.start()18    second→ Thread[#20,Thread-1,5,].start()19    firstThread[#19,Thread-0,5,].join()20    secondThread[#20,Thread-1,5,].join()2122    println("amount=" + amount1)23    println("counter=" + counter3)24  }25}
    outputamount=1
    counter=3
  1. amount ← 4, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    11def main(args: Array[String]): Unit = {12  val amount→ 4 = 41314  val first→ Thread[#19,Thread-0,5,main] = Thread(() => add(amount))15  val second→ Thread[#20,Thread-1,5,main] = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  second.start()19  first.join()
  2. def add(amount: Int): Unit =

    pass 1 of 2
    5def add(amount4: Int): Unit = {6  lock.synchronized {
  3. first.start()

    5def add(amount: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter0 + amount48  }9}1011def main(args: Array[String]): Unit = {12  val amount = 41314  val first = Thread(() => add(amount))15  val second = Thread(() => add(amount + 1))1617  firstThread[#19,Thread-0,5,main].start()18  secondThread[#20,Thread-1,5,main].start()19  first.join()20  second.join()
  4. def add(amount: Int): Unit =

    pass 2 of 2
    5def add(amount5: Int): Unit = {6  lock⟨Object A⟩.synchronized {7    counter = counter4 + amount58  }9}
  5. second ← Thread[#20,Thread-1,5,]

    17    first.start()18    second→ Thread[#20,Thread-1,5,].start()19    firstThread[#19,Thread-0,5,].join()20    secondThread[#20,Thread-1,5,].join()2122    println("amount=" + amount4)23    println("counter=" + counter9)24  }25}
    outputamount=4
    counter=9