Your question is Fix Multithreading Issues. Take a moment with it on the right.
Talk me through your thinking if you like. When you're confident, submit your answer and I'll grade it like a real screen (7/10 or better passes).
You are reviewing the Kotlin class below from an Android banking app. It caches exchange rates, notifies screens when a rate changes, and moves money between in-memory accounts. It passes a single-threaded demo but crashes and shows wrong numbers in production.
Find every multithreading issue in it. For each one, explain what can go wrong at runtime and show how you would fix it.
interface RatesListener {
// Implemented by Activities. Updates views.
fun onRateUpdated(pair: String, rate: Rate)
}
class Account(val id: String, var balance: BigDecimal)
class RatesRepository(private val api: RatesApi) {
private val cache = HashMap<String, Rate>()
private val listeners = ArrayList<RatesListener>()
var refreshCount = 0
fun addListener(listener: RatesListener) {
listeners.add(listener)
}
fun refresh(pairs: List<String>) {
for (pair in pairs) {
Thread {
// blocking network call
val rate = api.fetchRate(pair)
cache[pair] = rate
refreshCount++
for (listener in listeners) {
listener.onRateUpdated(pair, rate)
}
}.start()
}
}
fun getRate(pair: String): Rate? {
if (!cache.containsKey(pair)) {
cache[pair] = api.fetchRate(pair)
}
return cache[pair]
}
fun transfer(from: Account, to: Account, amount: BigDecimal) {
synchronized(from) {
synchronized(to) {
from.balance -= amount
to.balance += amount
}
}
}
}
Assume refresh, getRate, addListener and transfer can all be called from different threads, including the main thread, and that refresh can be called again before the previous one finishes.