Title here
Summary here
In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a mutex to safely access data across multiple threads.
import scala.collection.mutable
import java.util.concurrent.locks.ReentrantLock
// Container holds a map of counters; since we want to
// update it concurrently from multiple threads, we
// add a ReentrantLock to synchronize access.
// Note that locks must not be copied, so if this
// class is passed around, it should be done by
// reference.
class Container {
private val lock = new ReentrantLock()
private val counters = mutable.Map[String, Int]("a" -> 0, "b" -> 0)
// Lock before accessing counters; unlock
// it at the end of the function using a try-finally block.
def inc(name: String): Unit = {
lock.lock()
try {
counters(name) += 1
} finally {
lock.unlock()
}
}
def getCounters: Map[String, Int] = counters.toMap
}
object MutexExample extends App {
val c = new Container()
// This function increments a named counter
// in a loop.
def doIncrement(name: String, n: Int): Runnable = () => {
for (_ <- 1 to n) {
c.inc(name)
}
}
// Run several threads concurrently; note
// that they all access the same Container,
// and two of them access the same counter.
val threads = List(
new Thread(doIncrement("a", 10000)),
new Thread(doIncrement("a", 10000)),
new Thread(doIncrement("b", 10000))
)
threads.foreach(_.start())
threads.foreach(_.join())
println(c.getCounters)
}
Running the program shows that the counters updated as expected.
$ scala MutexExample.scala
Map(a -> 20000, b -> 10000)
Next, we’ll look at implementing this same state management task using only actors and message passing.
In this Scala version:
ReentrantLock
from java.util.concurrent.locks
instead of Go’s sync.Mutex
.Container
class encapsulates the lock and the counters.try-finally
block to ensure the lock is always released, similar to Go’s defer
.WaitGroup
with explicitly joining the threads at the end.doIncrement
function is defined as a method returning a Runnable
, which is used to create threads.This example demonstrates how to use mutexes in Scala to safely access shared state from multiple threads, achieving the same goal as the original Go program.