Reputation: 18034
Which of the following two snippets is more efficient and behaves correctly?
// snippet 1
var map = Map[String, Int]() // immutable map with var
map.synchronized(map += "hello" -> 1)
map.synchronized(map -= "hello")
// snippet 2
val mmap = scala.collection.mutable.Map[String, Int]()
mmap.synchronized(mmap += "hello" -> 1)
mmap.synchronized(mmap -= "hello")
EDIT: I am looking in the case of concurrent access to the map, where multiple different actors share the same map and want to modify it. Also the linked question deals with general case of var
and val
, while I need some insight on Map
collection type.
Upvotes: 4
Views: 1796
Reputation: 19527
soote: Is there a reason you cannot place this map inside an actor, and have other actors use messages to modify/read it?
Jus12: @soote On second thought, you are right! I will implement it using proper actor model.
soote is, indeed, right: since you're apparently using an actor system, the map should reside in an actor. And in general, when representing mutable state inside an actor, one should use an immutable data structure with a var
instead of a mutable data structure with a val
. The reason for this is to prevent that state from leaking outside the boundaries of the actor. Here is a concrete example using Akka:
case object GetState
case class Add(key: String, value: Int)
case class Remove(key: String)
class MyActor extends Actor {
val state = mutable.Map[String, Int]()
def receive = {
case GetState =>
sender ! state
case Add(k, v) =>
state += (k -> v)
case Remove(k) =>
state -= k
}
}
When the above actor receives a GetState
message, it sends its internal map to the sender. Since the map is mutable, the sender now has the ability to modify that map from outside the actor, thus allowing the possibility of corrupting the actor's state. To prevent this leak, restrict mutability to the actor itself:
class MyActor extends Actor {
var state = Map[String, Int]() // immutable map
def receive = {
case GetState =>
sender ! state
case Add(k, v) =>
state = state + (k -> v)
case Remove(k) =>
state = state - k
}
}
Now MyActor
can safely send its state to other actors because its state is an immutable map.
Upvotes: 0
Reputation: 15435
It depends as both mutable and immutable objects have their pro's and con's.
Immutable objects make concurrent programming easier, safer and you can easily reason about them. Most of the runtime errors that happen around the JVM concurrency is because of the shared mutable state.
If your objects become larger, making a copy of the object just for the sake of maintaining an immutable state does not make sense. You have to think wisely when you design your algorithm.
Upvotes: 1