Concurrency and Source Panels
Synchronized Counter
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
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]}")
}
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()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 1 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount2: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }7}left ← Thread[#19,Thread-0,5,]
17left→ Thread[#19,Thread-0,5,].start()18rightThread[#20,Thread-1,5,main].start()19left.join()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 2 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount2: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }7}right.start()
17left.start()18rightThread[#20,Thread-1,5,main].start()19left.join()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
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()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 1 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount1: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }7}pass 1 of 4 1fun addTwice(lock: Any, counter: IntArray, amount: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amountAll 4 passes — pass 1 is the card above pass lockamount1 — — 2 ⟨Object A⟩ 1 3 — — 4 — — pass 1 of 4 2repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }All 4 passes — pass 1 is the card above pass lockamount1 — — 2 ⟨Object A⟩ 1 3 — — 4 — — right.start()
17left.start()18rightThread[#20,Thread-1,5,main].start()19left.join()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 2 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount1: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }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
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()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 1 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount4: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }7}right.start()
17left.start()18rightThread[#20,Thread-1,5,main].start()19leftThread[#19,Thread-0,5,].join()20rightThread[#20,Thread-1,5,main].join()fun addTwice(lock: Any, counter: IntArray, amount: Int)
pass 2 of 21fun addTwice(lock⟨Object A⟩: Any, counter: IntArray, amount4: Int) {2 repeat(2) {3 synchronized(lock) {4 counter[0] += amount5 }6 }7}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