I want to create a thread-safe container that uses a Scala Map as a backing store. Rather than expose the user to the underlying Map, I would rather only expose a subset of its methods.
Example might look something like the following...
class MyContainer[A] {
def add(thing: A): Unit = {
backingStore = backingStore + (thing.uuid -> thing)
}
def filter(p: A => Boolean): Option[Iterable[A]] = {
val filteredThings = backingStore.values.filter(p)
if (filteredThings.isEmpty) None else Some(filteredThings)
}
def remove(uuid: UUID): Option[A] = backingStore.get(uuid) match {
case optionalThing @ Some(thing) =>
backingStore = backingStore - uuid; optionalThing
case None => None
}
@ volatile private[this] var backingStore = immutable.HashMap.empty[UUID, A]
}
...I suspect that even though the underlying backing store is immutable and its reference is volatile
, the container is not thread-safe.
Suppose that I have two separate threads running with access to an instance of the above container. Thread 1 filters the underlying collection and gets some results; at the same time Thread 2 removes an item. The results that thread one has might contain a reference to the item that Thread 2 removed? There might be other problems.
Am I correct that the above implementation is not thread-safe? What would be the most idiomatic way to make the above thread-safe using Scala?
Edit: I would prefer to avoid blocking and synchronization if possible. If blocking/synchronization must be used then is the volatile reference needed? And what would be the point of the immutable collection? Couldn't I just as well use a mutable collection?