Example Race Condition

With Threads

package com.glassthought.sandbox

class RaceConditionInducer {
  private var value = 0

  
  // @Synchronized // would fix this example race condition.
  fun incrementValue() {
    val storedValue = value

    Thread.sleep(10)

    println("Incrementing value from storedValue=$storedValue to ${storedValue + 1}")
    value = storedValue + 1
  }

  fun getValue() = value
}

fun main() {
  val raceConditionInducer = RaceConditionInducer()

  val threads = (1..10).map {
    Thread { raceConditionInducer.incrementValue() }
  }
  threads.forEach { it.start() }
  threads.forEach { it.join() }

  println("Value: ${raceConditionInducer.getValue()}")
}

Command to reproduce:

gt.sandbox.checkout.commit 0b65495f3299ff186efc \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run"

Recorded output of command:

> Task :app:checkKotlinGradlePluginConfigurationErrors SKIPPED
> Task :app:processResources NO-SOURCE
> Task :app:compileKotlin
> Task :app:compileJava NO-SOURCE
> Task :app:classes UP-TO-DATE

> Task :app:run
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Value: 1

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

With CoRoutines

package com.glassthought.sandbox

import kotlinx.coroutines.*
import kotlin.random.Random

class RaceConditionInducer {
  private var value = 0

  // Suspending function to simulate some work and induce a race condition
  suspend fun incrementValue() {
    val storedValue = value

    // Simulate delay to increase the likelihood of race conditions
    delay(10)

    println("Incrementing value from storedValue=$storedValue to ${storedValue + 1}")
    value = storedValue + 1
  }

  fun getValue() = value
}

fun main() = runBlocking {
  val raceConditionInducer = RaceConditionInducer()

  // Launch multiple coroutines to increment the value
  val jobs = List(10) {
    GlobalScope.launch {
      raceConditionInducer.incrementValue()
    }
  }

  // Wait for all coroutines to complete
  jobs.forEach { it.join() }

  println("Final Value: ${raceConditionInducer.getValue()}")
}

Command to reproduce:

gt.sandbox.checkout.commit a82a70441214360361c9 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run"

Recorded output of command:

> Task :app:checkKotlinGradlePluginConfigurationErrors SKIPPED
> Task :app:compileKotlin UP-TO-DATE
> Task :app:compileJava NO-SOURCE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE

> Task :app:run
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Incrementing value from storedValue=0 to 1
Final Value: 1

BUILD SUCCESSFUL in 704ms
2 actionable tasks: 1 executed, 1 up-to-date


Children
  1. Race Condition With Coroutines
  2. Race condition With Threads