Protect a shared counter with Kotlin's synchronized block.

synchronized block `synchronized(lock)` lets only one thread run the protected block at a time, so each increment sees a stable counter value.

Synchronized Counter

amount
SynchronizedCounter.kt
Replay: real traced execution (multi-file project)
fun addTwice(lock: Any, counter: IntArray, amount: Int) {
    repeat(2) {
        synchronized(lock) {
            counter[0] += amount
        }
    }
}

fun main() {
    val amount = 2
    val lock = Any()
    val counter = IntArray(1)

    val left = Thread { addTwice(lock, counter, amount) }
    val right = Thread { addTwice(lock, counter, amount) }

    left.start()
    right.start()
    left.join()
    right.join()

    println("amount=$amount")
    println("counter=${counter[0]}")
}
fun addTwice(lock: Any, counter: IntArray, amount: Int) {
    repeat(2) {
        synchronized(lock) {
            counter[0] += amount
        }
    }
}

fun main() {
    val amount = 1
    val lock = Any()
    val counter = IntArray(1)

    val left = Thread { addTwice(lock, counter, amount) }
    val right = Thread { addTwice(lock, counter, amount) }

    left.start()
    right.start()
    left.join()
    right.join()

    println("amount=$amount")
    println("counter=${counter[0]}")
}
fun addTwice(lock: Any, counter: IntArray, amount: Int) {
    repeat(2) {
        synchronized(lock) {
            counter[0] += amount
        }
    }
}

fun main() {
    val amount = 4
    val lock = Any()
    val counter = IntArray(1)

    val left = Thread { addTwice(lock, counter, amount) }
    val right = Thread { addTwice(lock, counter, amount) }

    left.start()
    right.start()
    left.join()
    right.join()

    println("amount=$amount")
    println("counter=${counter[0]}")
}
  1. amount ← 2, lock ← ⟨Object A⟩, left ← Thread[#19,Thread-0,5,main]

    9fun main() {10    val amount→ 2 = 2 //@amount=1, 411    val lock→ ⟨Object A⟩ = Any()12    val counter = IntArray(1)1314    val left→ Thread[#19,Thread-0,5,main] = Thread { addTwice(lock, counter, amount) }15    val right→ Thread[#20,Thread-1,5,main] = Thread { addTwice(lock, counter, amount) }1617    leftThread[#19,Thread-0,5,main].start()18    right.start()
  2. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 1 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount2: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  3. left ← Thread[#19,Thread-0,5,]

    17left→ Thread[#19,Thread-0,5,].start()18rightThread[#20,Thread-1,5,main].start()19left.join()
  4. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 2 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount2: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  5. right.start()

    17left.start()18rightThread[#20,Thread-1,5,main].start()19left.join()
  6. left.join()

    18    right.start()19    leftThread[#19,Thread-0,5,].join()20    rightThread[#20,Thread-1,5,].join()2122    println("amount=$amount2")23    println("counter=${counter[0]8}")24}
    outputamount=2
    counter=8
  1. amount ← 1, lock ← ⟨Object A⟩, left ← Thread[#19,Thread-0,5,main]

    9fun main() {10    val amount→ 1 = 111    val lock→ ⟨Object A⟩ = Any()12    val counter = IntArray(1)1314    val left→ Thread[#19,Thread-0,5,main] = Thread { addTwice(lock, counter, amount) }15    val right→ Thread[#20,Thread-1,5,main] = Thread { addTwice(lock, counter, amount) }1617    leftThread[#19,Thread-0,5,main].start()18    rightThread[#20,Thread-1,5,main].start()19    left.join()
  2. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 1 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount1: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  3. pass 1 of 4
    1fun addTwice(lock: Any, counter: IntArray, amount: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount
    All 4 passes — pass 1 is the card above
    passlockamount
    1
    2⟨Object A⟩1
    3
    4
  4. pass 1 of 4
    2repeat(2) {3    synchronized(lock) {4        counter[0] += amount5    }
    All 4 passes — pass 1 is the card above
    passlockamount
    1
    2⟨Object A⟩1
    3
    4
  5. right.start()

    17left.start()18rightThread[#20,Thread-1,5,main].start()19left.join()
  6. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 2 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount1: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  7. left.join()

    18    right.start()19    leftThread[#19,Thread-0,5,].join()20    rightThread[#20,Thread-1,5,].join()2122    println("amount=$amount1")23    println("counter=${counter[0]4}")24}
    outputamount=1
    counter=4
  1. amount ← 4, lock ← ⟨Object A⟩, left ← Thread[#19,Thread-0,5,main]

    9fun main() {10    val amount→ 4 = 411    val lock→ ⟨Object A⟩ = Any()12    val counter = IntArray(1)1314    val left→ Thread[#19,Thread-0,5,main] = Thread { addTwice(lock, counter, amount) }15    val right→ Thread[#20,Thread-1,5,main] = Thread { addTwice(lock, counter, amount) }1617    leftThread[#19,Thread-0,5,main].start()18    rightThread[#20,Thread-1,5,main].start()19    left.join()
  2. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 1 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount4: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  3. right.start()

    17left.start()18rightThread[#20,Thread-1,5,main].start()19leftThread[#19,Thread-0,5,].join()20rightThread[#20,Thread-1,5,main].join()
  4. fun addTwice(lock: Any, counter: IntArray, amount: Int)

    pass 2 of 2
    1fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount4: Int) {2    repeat(2) {3        synchronized(lock) {4            counter[0] += amount5        }6    }7}
  5. right ← Thread[#20,Thread-1,5,]

    19    left.join()20    right→ Thread[#20,Thread-1,5,].join()2122    println("amount=$amount4")23    println("counter=${counter[0]16}")24}
    outputamount=4
    counter=16