Issue unique ticket numbers from two threads with AtomicInteger.

atomic-update Atomic types make a read-modify-write operation indivisible, so each thread receives a distinct ticket number.

Atomic Ticket

start
AtomicTicket.scala
Replay: real traced execution (multi-file project)
import java.util.concurrent.atomic.AtomicInteger

object Main {
  val next = new AtomicInteger(0)
  var firstTicket = 0
  var secondTicket = 0

  def firstWork(): Unit = {
    firstTicket = next.getAndIncrement()
  }

  def secondWork(): Unit = {
    secondTicket = next.getAndIncrement()
  }

  def main(args: Array[String]): Unit = {
    val start = 40
    next.set(start)

    val first = Thread(() => firstWork())
    val second = Thread(() => secondWork())

    first.start()
    second.start()
    first.join()
    second.join()

    val low = Math.min(firstTicket, secondTicket)
    val high = Math.max(firstTicket, secondTicket)
    println("start=" + start)
    println("tickets=" + low + "," + high)
  }
}
import java.util.concurrent.atomic.AtomicInteger

object Main {
  val next = new AtomicInteger(0)
  var firstTicket = 0
  var secondTicket = 0

  def firstWork(): Unit = {
    firstTicket = next.getAndIncrement()
  }

  def secondWork(): Unit = {
    secondTicket = next.getAndIncrement()
  }

  def main(args: Array[String]): Unit = {
    val start = 10
    next.set(start)

    val first = Thread(() => firstWork())
    val second = Thread(() => secondWork())

    first.start()
    second.start()
    first.join()
    second.join()

    val low = Math.min(firstTicket, secondTicket)
    val high = Math.max(firstTicket, secondTicket)
    println("start=" + start)
    println("tickets=" + low + "," + high)
  }
}
import java.util.concurrent.atomic.AtomicInteger

object Main {
  val next = new AtomicInteger(0)
  var firstTicket = 0
  var secondTicket = 0

  def firstWork(): Unit = {
    firstTicket = next.getAndIncrement()
  }

  def secondWork(): Unit = {
    secondTicket = next.getAndIncrement()
  }

  def main(args: Array[String]): Unit = {
    val start = 100
    next.set(start)

    val first = Thread(() => firstWork())
    val second = Thread(() => secondWork())

    first.start()
    second.start()
    first.join()
    second.join()

    val low = Math.min(firstTicket, secondTicket)
    val high = Math.max(firstTicket, secondTicket)
    println("start=" + start)
    println("tickets=" + low + "," + high)
  }
}
  1. start ← 40, next ← 40, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val start→ 40 = 40 //@start=10, 10018  next→ 40.set(start40)1920  val first→ Thread[#19,Thread-0,5,main] = Thread(() => firstWork())21  val second→ Thread[#20,Thread-1,5,main] = Thread(() => secondWork())2223  firstThread[#19,Thread-0,5,main].start()24  second.start()25  first.join()
  2. first.start()

    8def firstWork(): Unit = {9  firstTicket = next40.getAndIncrement()10}1112def secondWork(): Unit = {13  secondTicket = next.getAndIncrement()14}1516def main(args: Array[String]): Unit = {17  val start = 40 //@start=10, 10018  next.set(start)1920  val first = Thread(() => firstWork())21  val second = Thread(() => secondWork())2223  firstThread[#19,Thread-0,5,main].start()24  secondThread[#20,Thread-1,5,main].start()25  first.join()26  second.join()
  3. low ← 40, high ← 41

    12  def secondWork(): Unit = {13    secondTicket = next41.getAndIncrement()14  }1516  def main(args: Array[String]): Unit = {17    val start = 40 //@start=10, 10018    next.set(start)1920    val first = Thread(() => firstWork())21    val second = Thread(() => secondWork())2223    first.start()24    secondThread[#20,Thread-1,5,main].start()25    firstThread[#19,Thread-0,5,].join()26    secondThread[#20,Thread-1,5,].join()2728    val low→ 40 = Math.min(firstTicket40, secondTicket41)29    val high→ 41 = Math.max(firstTicket40, secondTicket41)30    println("start=" + start40)31    println("tickets=" + low40 + "," + high41)32  }33}
    outputstart=40
    tickets=40,41
  1. start ← 10, next ← 10, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val start→ 10 = 1018  next→ 10.set(start10)1920  val first→ Thread[#19,Thread-0,5,main] = Thread(() => firstWork())21  val second→ Thread[#20,Thread-1,5,main] = Thread(() => secondWork())2223  firstThread[#19,Thread-0,5,main].start()24  second.start()25  first.join()
  2. first.start()

    8def firstWork(): Unit = {9  firstTicket = next10.getAndIncrement()10}1112def secondWork(): Unit = {13  secondTicket = next.getAndIncrement()14}1516def main(args: Array[String]): Unit = {17  val start = 1018  next.set(start)1920  val first = Thread(() => firstWork())21  val second = Thread(() => secondWork())2223  firstThread[#19,Thread-0,5,main].start()24  secondThread[#20,Thread-1,5,main].start()25  first.join()26  second.join()
  3. low ← 10, high ← 11

    12  def secondWork(): Unit = {13    secondTicket = next11.getAndIncrement()14  }1516  def main(args: Array[String]): Unit = {17    val start = 1018    next.set(start)1920    val first = Thread(() => firstWork())21    val second = Thread(() => secondWork())2223    first.start()24    secondThread[#20,Thread-1,5,main].start()25    firstThread[#19,Thread-0,5,].join()26    secondThread[#20,Thread-1,5,].join()2728    val low→ 10 = Math.min(firstTicket10, secondTicket11)29    val high→ 11 = Math.max(firstTicket10, secondTicket11)30    println("start=" + start10)31    println("tickets=" + low10 + "," + high11)32  }33}
    outputstart=10
    tickets=10,11
  1. start ← 100, next ← 100, first ← Thread[#19,Thread-0,5,main], second ← Thread[#20,Thread-1,5,main]

    16def main(args: Array[String]): Unit = {17  val start→ 100 = 10018  next→ 100.set(start100)1920  val first→ Thread[#19,Thread-0,5,main] = Thread(() => firstWork())21  val second→ Thread[#20,Thread-1,5,main] = Thread(() => secondWork())2223  firstThread[#19,Thread-0,5,main].start()24  second.start()25  first.join()
  2. def firstWork(): Unit =

    8def firstWork(): Unit = {9  firstTicket = next100.getAndIncrement()10}
  3. first ← Thread[#19,Thread-0,5,]

    23first→ Thread[#19,Thread-0,5,].start()24secondThread[#20,Thread-1,5,main].start()25first.join()26second.join()
  4. def secondWork(): Unit =

    12def secondWork(): Unit = {13  secondTicket = next101.getAndIncrement()14}
  5. second ← Thread[#20,Thread-1,5,], low ← 100, high ← 101

    23    first.start()24    second→ Thread[#20,Thread-1,5,].start()25    firstThread[#19,Thread-0,5,].join()26    secondThread[#20,Thread-1,5,].join()2728    val low→ 100 = Math.min(firstTicket100, secondTicket101)29    val high→ 101 = Math.max(firstTicket100, secondTicket101)30    println("start=" + start100)31    println("tickets=" + low100 + "," + high101)32  }33}
    outputstart=100
    tickets=100,101