Threads, @Volatile and synchronized

Runtime, build and Gradle Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Pick the fix

Two threads each run hits++ 10,000 times on a @Volatile var hits = 0. The total is often below 20,000. Fix?

Options
Hint 1 of 1

Is ++ one step or three?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Use AtomicInteger.incrementAndGet() or a synchronized block

Correct. The increment must be atomic, not just visible.

Why not the others?
  • B Mark it @Volatile twice. Not a thing, and volatile isn't the problem.
  • C Make it a val. Then it can't change.
  • D Add Thread.sleep between increments. Hides the race sometimes.

30-second answer

When threads share mutable data, you need visibility and atomicity. @Volatile makes writes visible to other threads but doesn't make count++ atomic. synchronized (or a lock) makes a block atomic and visible. Atomic classes like AtomicInteger do single-value updates without locks. With coroutines, prefer Mutex, confinement to one thread, or a StateFlow's update instead.

Practise saying it · 30 s. No recording, just a timer

Explain volatile vs synchronized.

Say your answer out loud, then check which of these points you covered:

  • Volatile = visibility
  • Synchronized = atomic + visible
  • Atomics for single values
  • Mutex or confinement with coroutines

Deep dive

count++ is read, add, write: three steps that can interleave.

Double-checked locking needs a volatile field.

by lazy is synchronized by default.

Don't call suspend functions while holding a Java lock.

An atomic counter Compile-checked · Kotlin 2.4.21
class HitCounter {
    private val hits = java.util.concurrent.atomic.AtomicInteger(0)
    fun hit(): Int = hits.incrementAndGet()
    val total: Int get() = hits.get()
}

Common mistakes

  • Thinking @Volatile makes increments safe.
  • Synchronizing on a public object others can lock.
  • Blocking locks inside coroutines.

Senior take & follow-ups

Separate visibility from atomicity; then give the coroutine-friendly options.

Follow-up questions

Think of your answer first, then open the hint.

  1. Is by lazy thread-safe?

    Show hint

    Yes, by default it uses a lock.

  2. Why not hold a lock across a suspend call?

    Show hint

    The coroutine may resume on another thread and the lock blocks a thread.

Suggest a fix if something here is wrong or out of date.