以下哪两个片段效率更高,行为正确?
// 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")
编辑:我正在查看并发访问地图的情况,其中多个不同的actor共享同一个地图并想要修改它。此外,相关问题还涉及var
和val
的一般情况,而我需要对Map
集合类型有所了解。
答案 0 :(得分:1)
这取决于可变对象和不可变对象都有他们的专业和对象。
不可变对象使并发编程更容易,更安全,您可以轻松推理它们。围绕JVM并发发生的大多数运行时错误都是由于共享的可变状态。
如果您的对象变大,仅仅为了维持不可变状态而复制对象是没有意义的。在设计算法时,你必须明智地思考。
答案 1 :(得分:0)
实际上,soote是正确的:因为你显然使用的是演员系统,所以地图应该存在于演员中。通常,当在actor中表示可变状态时,应该使用具有soote:有没有理由你不能把这个地图放在一个演员里面,让其他演员使用消息来修改/阅读它?
Jus12:@soote再想一想,你是对的!我将使用适当的actor模型来实现它。
var
的不可变数据结构,而不是具有val
的可变数据结构。这样做的原因是为了防止该状态泄漏到演员的边界之外。以下是使用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
}
}
当上述演员收到GetState
消息时,它会将其内部地图发送给发件人。由于地图是可变的,因此发送者现在能够从演员之外修改该地图,从而允许破坏演员状态的可能性。为了防止这种泄漏,限制对actor本身的可变性:
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
}
}
现在MyActor
可以安全地将其状态发送给其他actor,因为它的状态是不可变的映射。