Protected
Akka’s STM implements the concept in Clojure’s STM view on state in general. Please take the time to read this excellent document and view this presentation by Rich Hickey (the genius behind Clojure), since it forms the basis of Akka’s view on STM and state in general.
It is based on two concepts:
The Persistent Datastructures consist of a Map and Vector and are Scala ports of Clojure’s Map and Vector. The Managed References are implemented using the excellent Multiverse STM.
Akka's STM only works with immutable data. This can be costly if you have large datastructures and are using a naive copy-on-write. In order to make working with immutable datastructures fast enough Akka provides what is called Persistent Datastructures. Akka currently has two different ones:
These are Scala ports of Clojure's datastructures. They are immutable and each update creates a completely new version but they are using clever structural sharing in order to make them almost as fast, for both read and update, as regular mutable Maps.
This illustration is taken from Rich Hickey's presentation. Copyright Rich Hickey 2009.

This is some of its API. It extends Scala's RandomAccessSeq:
Creating a Vector:
This is some of its API. It extends Scala's Map:
Creating a HashTrie:
Managed References are memory cells that point to immutable data. The data, e.g. the Ref's value can never change, but the Ref can be swapped with some other immutable data. E.g. the Ref itself is mutable but only within a transaction. If you try to modify a Ref outside a transaction you will get an exception. Ref's separate identity from value.
Here is an example of how you can create a Ref. It is using one of the two persistent datastructures that Akka has; the HashTrie, which is an immutable Map but with near constant time access and modification operations.
The Ref is monadic and is possible to use within a for-comprehension. Here are some examples:
You can also create Refs directly like this:
Akka provides three different datastructures that are managed by the STM.
Map and Vector look like regular mutable datastructures, they even implement the standard Scala 'Map' and 'RandomAccessSeq' interfaces. But they are implemented using persistent datastructures and managed references under the hood. Therefore they are safe to use in a concurrent environment. They can only be modified inside the scope of an STM transaction (see below for details).
These managed datastructures always have to be created within a message send since that will trigger a transaction. It means that you always have to either declare them as 'lazy' or do lazy initialization by some other means.
Here is how you create these:
You can manage transactions in two different ways:
Update:
Read:
By default the STM is always turned on. This means that Actors and Active Objects will have the transaction semantics of “transaction supports”. E.g. they will happily join an existing transaction but not start a new one.
If you would like to completely turn off the STM since you know that you are not using any Transactional datastructures at all then you can either invoke:
Or you can turn it off in the ‘akka.conf’ configuration file.
Turning it off will yield better performance since the STM adds a certain overhead with its bookkeeping.
Akka's STM is based on Multiverse. Multiverse has a configuration file that you can edit to tune the STM.
Generally best performance is accomplished by setting these options (which are already set for you by the runtime system):
Here is the full configuration file, which resides in 'AKKA_HOME/config'. You can use it to fine-tune the STM, to get Multiverse to dump the generated code, to perform sanity checks etc.
Software Transactional Memory (STM)
An STM turns the Java heap into a transactional data set with begin/commit/rollback semantics. Very much like a regular database. It implements the first three letters in ACID; ACI:
- Atomic
- Consistent
- Isolated
Overview of STM
Akka’s STM implements the concept in Clojure’s STM view on state in general. Please take the time to read this excellent document and view this presentation by Rich Hickey (the genius behind Clojure), since it forms the basis of Akka’s view on STM and state in general.
It is based on two concepts:
- Managed References: Memory cells, holding an immutable value, that implement CAS (Compare-And-Swap) semantics and are managed and enforced by the STM for coordinated changes across many References.
- Persistent Datastructures: Immutable but with constant time access and modification. The use of structural sharing and an insert or update does not ruin the old structure, hence “persistent”. Makes working with immutable composite types fast.
The Persistent Datastructures consist of a Map and Vector and are Scala ports of Clojure’s Map and Vector. The Managed References are implemented using the excellent Multiverse STM.
Persistent Datastructures
Akka's STM only works with immutable data. This can be costly if you have large datastructures and are using a naive copy-on-write. In order to make working with immutable datastructures fast enough Akka provides what is called Persistent Datastructures. Akka currently has two different ones:
- HashTrie (http://en.wikipedia.org/wiki/Trie ) - which implements 'scala.Map'
- Vector - which implements 'scala.RandomAccessSeq'
These are Scala ports of Clojure's datastructures. They are immutable and each update creates a completely new version but they are using clever structural sharing in order to make them almost as fast, for both read and update, as regular mutable Maps.
This illustration is taken from Rich Hickey's presentation. Copyright Rich Hickey 2009.

Persistent Vector
This is some of its API. It extends Scala's RandomAccessSeq:
def apply(i: Int): T def +[A >: T](obj: A): Vector[A] def pop: HashTrie[K, A] // remove tail def update[A >: T](i: Int, obj: A): Vector[A]
Creating a Vector:
import se.scalablesolutions.akka.collection._ val vector = new Vector[T]
Persistent Map (HashTrie)
This is some of its API. It extends Scala's Map:
def get(key: K): V def +[A >: V](pair: (K, A)): HashTrie[K, A] def -(key: K): HashTrie[K, A] def empty[A]: HashTrie[K, A]
Creating a HashTrie:
import se.scalablesolutions.akka.collection._ val hashTrie = new HashTrie[K, V]
Managed References
Managed References are memory cells that point to immutable data. The data, e.g. the Ref's value can never change, but the Ref can be swapped with some other immutable data. E.g. the Ref itself is mutable but only within a transaction. If you try to modify a Ref outside a transaction you will get an exception. Ref's separate identity from value.
Here is an example of how you can create a Ref. It is using one of the two persistent datastructures that Akka has; the HashTrie, which is an immutable Map but with near constant time access and modification operations.
val ref = TransactionalState.newRef(HashTrie[String, User]()) val users = ref.get val newUsers = users + (“bill” -> new User(“bill”, “secret”) // creates new HashTrie ref.swap(newUsers)
The Ref is monadic and is possible to use within a for-comprehension. Here are some examples:
val usersRef = TransactionalState.newRef(HashTrie[String, User]()) for (users <- usersRef) { users + (name -> user) } val user = for (users <- usersRef) yield { users(name) } for { users <- usersRef user <- users roles <- rolesRef role <- roles if user.hasRole(role) } { ... // do stuff }
You can also create Refs directly like this:
val ref = TransactionalRef() ref.swap(..)
Managed Datastructures
Akka provides three different datastructures that are managed by the STM.
- Map
- Vector
- Ref
Map and Vector look like regular mutable datastructures, they even implement the standard Scala 'Map' and 'RandomAccessSeq' interfaces. But they are implemented using persistent datastructures and managed references under the hood. Therefore they are safe to use in a concurrent environment. They can only be modified inside the scope of an STM transaction (see below for details).
These managed datastructures always have to be created within a message send since that will trigger a transaction. It means that you always have to either declare them as 'lazy' or do lazy initialization by some other means.
Here is how you create these:
// Scala version lazy val map = TransactionalState.newMap[String, Person] lazy val vector = TransactionalState.newVector[Address] lazy val ref = TransactionalState.newRef[Account]
Managing Transactions
You can manage transactions in two different ways:
- Using 'atomic' blocks
- Using for-comprehensions (monadic API)
Atomic Block API
import se.scalablesolutions.akka.stm.Transaction._ atomic { .. // do something within a transaction } atomic(maxNrOfRetries) { .. // do something within a transaction } atomicReadOnly { .. // do something within a transaction } atomically { .. // try to do something } orElse { .. // if tx clash; try do do something else }
Monadic API using for-comprehensions
Update:
import se.scalablesolutions.akka.stm.Transaction val userStorage = TransactionalState.newMap[String, User] for (tx <- Transaction()) { userStorage.put(user.name, user) // transactional }
Read:
import se.scalablesolutions.akka.stm.Transaction val userStorage = TransactionalState.newMap[String, User] val users = for { tx <- Transaction() name <- userNames if userStorage.contains(name) } yield userStorage.get(name) // transactional
Using STM outside of Akka Actors
If you are using the STM constructs outside of an Actor, you need to provide it with an implicit TransactionFamilyNamedef foo = { implicit val tfn = "uniquename" //TransactionFamilyName atomic { //Do stuff } }
How to disable the STM?
By default the STM is always turned on. This means that Actors and Active Objects will have the transaction semantics of “transaction supports”. E.g. they will happily join an existing transaction but not start a new one.
If you would like to completely turn off the STM since you know that you are not using any Transactional datastructures at all then you can either invoke:
// Scala version TransactionManagement.disableTransactions
Or you can turn it off in the ‘akka.conf’ configuration file.
<akka> <stm> service = off </stm> </akka>
Turning it off will yield better performance since the STM adds a certain overhead with its bookkeeping.
How to tune the STM?
Akka's STM is based on Multiverse. Multiverse has a configuration file that you can edit to tune the STM.
Generally best performance is accomplished by setting these options (which are already set for you by the runtime system):
-Dorg.multiverse.MuliverseConstants.sanityChecks=false -Dorg.multiverse.api.GlobalStmInstance.factorymethod=org.multiverse.stms.alpha.AlphaStm.fastDebug
Here is the full configuration file, which resides in 'AKKA_HOME/config'. You can use it to fine-tune the STM, to get Multiverse to dump the generated code, to perform sanity checks etc.
# ============================================ # ===== Multiverse JVM Options Reference ===== # ============================================ # All these properties can be set on the commandline using '-D<option-name>=<value>' # a flag that is used to enable sanity checks. # default=true org.multiverse.MuliverseConstants.sanityChecks=<type:boolean> # a flag that enables to dump of bytecode of the instrumented classes to the tmp directory # This is very interesting feature for debugging of the instrumentation # default=false org.multiverse.stms.alpha.instrumentation.MultiverseJavaAgent.dumpBytecode=<type:boolean> # a string containing the full path to a static no-arg factory method that is used to create the global stm. # default = org.multiverse.stms.alpha.AlphaStm.createDebug org.multiverse.api.GlobalStmInstance.factorymethod=<type:string> # a flag that enables the reuse of the FailedToObtainLocksException exception instance # default = true org.multiverse.api.exceptions.FailedToObtainLocksException.reuse=<type:boolean> # a flag that enables the reuse of the LoadLockedException exception instance # default = true org.multiverse.api.exceptions.LoadLockedException.reuse=<type:boolean> # a flag that enables the reuse of the LoadLockedException exception instance # default = true org.multiverse.api.exceptions.LoadTooOldVersionException.reuse=<type:boolean> # a flag that enables the reuse of the RetryError exception instance # default = true org.multiverse.api.exceptions.RetryError.reuse=<type:boolean> # a flag that enables the reuse of the WriteConflictException exception instance # default = true org.multiverse.api.exceptions.WriteConflictException.reuse=<type:boolean>

