Skip to content

Instantly share code, notes, and snippets.

@Ghurtchu
Last active April 2, 2023 22:56
Show Gist options
  • Save Ghurtchu/2f1d1465271a302643cd87762b3b8e7d to your computer and use it in GitHub Desktop.
Save Ghurtchu/2f1d1465271a302643cd87762b3b8e7d to your computer and use it in GitHub Desktop.
In-Memory Concurrent Key-Value Cache
object ConcurrentInMemoryCacheImpl {
trait Cache[K, V] {
type F
def put(k: K, v: V): Unit
def get(k: K): Option[V]
def remove(k: K): Option[V]
def update(k: K, v: V): Unit
def value: F
}
object Cache {
import scala.collection.concurrent.TrieMap
def apply[K, V]: Cache[K, V] = new Cache[K, V] {
override type F = TrieMap[K, V]
private val mapRef = Ref(TrieMap.empty[K, V])
override def put(k: K, v: V): Unit = mapRef.modify { map =>
map.put(k, v)
(map, ())
}
override def get(k: K): Option[V] = mapRef.modify { map => (map, map.get(k)) }
override def remove(k: K): Option[V] = mapRef.modify { map =>
val removed = map.remove(k)
(map, removed)
}
override def update(k: K, v: V): Unit = mapRef.modify { map =>
map.update(k, v)
(map, ())
}
override def value: TrieMap[K, V] = mapRef.get
}
trait Atomically[A] {
def get: A
def modify[B](f: A => (A, B)): B
}
import java.util.concurrent.atomic.AtomicReference
final class Ref[A](ar: AtomicReference[A]) extends Atomically[A] {
override def modify[B](f: A => (A, B)): B = {
@scala.annotation.tailrec
def spin(): B = {
val oldState = get
val (newState, b) = f(oldState)
if (ar.compareAndSet(oldState, newState)) b else spin()
}
spin()
}
override def get: A = ar.get
}
object Ref {
def apply[A](a: => A): Ref[A] = new Ref[A](new AtomicReference[A](a))
}
}
}
@Ghurtchu
Copy link
Author

Ghurtchu commented Apr 2, 2023

Let's try the same on simple mutable @volatile variable:

concurrently {
  @volatile var num = 0

  runThreads(amount = 10, task = num += 1)
  runThreads(amount = 10, task = num -= 1)

  Thread sleep 3000

  println(num)
}

Output: -15173, -4728, 8123, 12421, 5766, 7568, -904, -34940, 1254, 200 - didn't pass even one time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment