Give each worker thread its own context value.

thread-local A `ThreadLocal` stores a value separately for each thread, so worker context can be read without sharing a mutable field.

Thread Local Context

suffix
ThreadLocalContext.scala
Replay: real traced execution (multi-file project)
object Main {
  val context = new ThreadLocal[String]()
  var firstValue = ""
  var secondValue = ""

  def readAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    firstValue = context.get() + ":" + number
  }

  def writeAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    secondValue = context.get() + ":" + number
  }

  def main(args: Array[String]): Unit = {
    val suffix = "api"

    val reader = Thread(() => readAction("read", suffix, 8))
    val writer = Thread(() => writeAction("write", suffix, 9))

    reader.start()
    writer.start()
    reader.join()
    writer.join()

    println(firstValue)
    println(secondValue)
  }
}
object Main {
  val context = new ThreadLocal[String]()
  var firstValue = ""
  var secondValue = ""

  def readAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    firstValue = context.get() + ":" + number
  }

  def writeAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    secondValue = context.get() + ":" + number
  }

  def main(args: Array[String]): Unit = {
    val suffix = "db"

    val reader = Thread(() => readAction("read", suffix, 8))
    val writer = Thread(() => writeAction("write", suffix, 9))

    reader.start()
    writer.start()
    reader.join()
    writer.join()

    println(firstValue)
    println(secondValue)
  }
}
object Main {
  val context = new ThreadLocal[String]()
  var firstValue = ""
  var secondValue = ""

  def readAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    firstValue = context.get() + ":" + number
  }

  def writeAction(name: String, suffix: String, number: Int): Unit = {
    context.set(name + "-" + suffix)
    secondValue = context.get() + ":" + number
  }

  def main(args: Array[String]): Unit = {
    val suffix = "cache"

    val reader = Thread(() => readAction("read", suffix, 8))
    val writer = Thread(() => writeAction("write", suffix, 9))

    reader.start()
    writer.start()
    reader.join()
    writer.join()

    println(firstValue)
    println(secondValue)
  }
}
  1. suffix ← api, reader ← Thread[#19,Thread-0,5,main], writer ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val suffix→ api = "api" //@suffix="db", "cache"1819  val reader→ Thread[#19,Thread-0,5,main] = Thread(() => readAction("read", suffix, 8))20  val writer→ Thread[#20,Thread-1,5,main] = Thread(() => writeAction("write", suffix, 9))2122  readerThread[#19,Thread-0,5,main].start()23  writerThread[#20,Thread-1,5,main].start()24  reader.join()25  writer.join()
  2. def readAction(name: String, suffix: String, number: Int): Unit =

    6def readAction(nameread: String, suffixapi: String, number8: Int): Unit = {7  context⟨ThreadLocal A⟩.set(nameread + "-" + suffixapi)8  firstValue = context⟨ThreadLocal A⟩.get() + ":" + number89}
  3. writer.start()

    22reader.start()23writerThread[#20,Thread-1,5,main].start()24readerThread[#19,Thread-0,5,].join()25writerThread[#20,Thread-1,5,main].join()2627println(firstValue)
  4. def writeAction(name: String, suffix: String, number: Int): Unit =

    11def writeAction(namewrite: String, suffixapi: String, number9: Int): Unit = {12  context⟨ThreadLocal A⟩.set(namewrite + "-" + suffixapi)13  secondValue = context⟨ThreadLocal A⟩.get() + ":" + number914}
  5. writer ← Thread[#20,Thread-1,5,]

    24    reader.join()25    writer→ Thread[#20,Thread-1,5,].join()2627    println(firstValueread-api:8)28    println(secondValuewrite-api:9)29  }30}
    outputread-api:8
    write-api:9
  1. suffix ← db, reader ← Thread[#19,Thread-0,5,main], writer ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val suffix→ db = "db"1819  val reader→ Thread[#19,Thread-0,5,main] = Thread(() => readAction("read", suffix, 8))20  val writer→ Thread[#20,Thread-1,5,main] = Thread(() => writeAction("write", suffix, 9))2122  readerThread[#19,Thread-0,5,main].start()23  writerThread[#20,Thread-1,5,main].start()24  reader.join()25  writer.join()
  2. def readAction(name: String, suffix: String, number: Int): Unit =

    6def readAction(nameread: String, suffixdb: String, number8: Int): Unit = {7  context⟨ThreadLocal A⟩.set(nameread + "-" + suffixdb)8  firstValue = context⟨ThreadLocal A⟩.get() + ":" + number89}
  3. writer.start()

    22reader.start()23writerThread[#20,Thread-1,5,main].start()24readerThread[#19,Thread-0,5,].join()25writer.join()
  4. def writeAction(name: String, suffix: String, number: Int): Unit =

    11def writeAction(namewrite: String, suffixdb: String, number9: Int): Unit = {12  context.set(name + "-" + suffix)
  5. writer ← Thread[#20,Thread-1,5,]

    11  def writeAction(name: String, suffix: String, number: Int): Unit = {12    context⟨ThreadLocal A⟩.set(namewrite + "-" + suffixdb)13    secondValue = context⟨ThreadLocal A⟩.get() + ":" + number914  }1516  def main(args: Array[String]): Unit = {17    val suffix = "db"1819    val reader = Thread(() => readAction("read", suffix, 8))20    val writer = Thread(() => writeAction("write", suffix, 9))2122    reader.start()23    writer.start()24    reader.join()25    writer→ Thread[#20,Thread-1,5,].join()2627    println(firstValueread-db:8)28    println(secondValuewrite-db:9)29  }30}
    outputread-db:8
    write-db:9
  1. suffix ← cache, reader ← Thread[#19,Thread-0,5,main], writer ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val suffix→ cache = "cache"1819  val reader→ Thread[#19,Thread-0,5,main] = Thread(() => readAction("read", suffix, 8))20  val writer→ Thread[#20,Thread-1,5,main] = Thread(() => writeAction("write", suffix, 9))2122  readerThread[#19,Thread-0,5,main].start()23  writerThread[#20,Thread-1,5,main].start()24  reader.join()25  writer.join()
  2. def readAction(name: String, suffix: String, number: Int): Unit =

    6def readAction(nameread: String, suffixcache: String, number8: Int): Unit = {7  context⟨ThreadLocal A⟩.set(nameread + "-" + suffixcache)8  firstValue = context.get() + ":" + number9}
  3. writer.start()

    6def readAction(name: String, suffix: String, number: Int): Unit = {7  context⟨ThreadLocal A⟩.set(nameread + "-" + suffixcache)8  firstValue = context.get() + ":" + number9}1011def writeAction(name: String, suffix: String, number: Int): Unit = {12  context.set(name + "-" + suffix)13  secondValue = context.get() + ":" + number14}1516def main(args: Array[String]): Unit = {17  val suffix = "cache"1819  val reader = Thread(() => readAction("read", suffix, 8))20  val writer = Thread(() => writeAction("write", suffix, 9))2122  reader.start()23  writerThread[#20,Thread-1,5,main].start()24  readerThread[#19,Thread-0,5,main].join()25  writer.join()
  4. def writeAction(name: String, suffix: String, number: Int): Unit =

    7  context.set(name + "-" + suffix)8  firstValue = context⟨ThreadLocal A⟩.get() + ":" + number89}1011def writeAction(namewrite: String, suffixcache: String, number9: Int): Unit = {12  context⟨ThreadLocal A⟩.set(namewrite + "-" + suffixcache)13  secondValue = context⟨ThreadLocal A⟩.get() + ":" + number914}
  5. reader ← Thread[#19,Thread-0,5,]

    23    writer.start()24    reader→ Thread[#19,Thread-0,5,].join()25    writerThread[#20,Thread-1,5,].join()2627    println(firstValueread-cache:8)28    println(secondValuewrite-cache:9)29  }30}
    outputread-cache:8
    write-cache:9