在 Scala 中混合的最佳实践 concurrent.Map

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18660769/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:37:53  来源:igfitidea点击:

Best practices for mixing in Scala concurrent.Map

scalaconcurrencyhashmap

提问by Mike Slinn

The ScalaDocsays this about concurrentMap: "Deprecated (Since version 2.10.0) Use scala.collection.concurrent.Mapinstead." Unfortunately, the rest of the Scala docshas not been updated and still references concurrentMap.

ScalaDoc“已过时(从版本2.10.0)用途:说这约concurrentMapscala.collection.concurrent.Map来代替。” 不幸的是,Scala 文档其余部分尚未更新并且仍然引用concurrentMap.

I tried to mix in concurrent.Mapinto a HashMap, with the following results:

我试图混入concurrent.Map一个HashMap,结果如下:

scala> val mmap = new mutable.HashMap[String, String] with collection.concurrent.Map[String, String]
<console>:16: error: object creation impossible, since:
it has 4 unimplemented members.
/** As seen from anonymous class $anon, the missing signatures are as follows.
 *  For convenience, these are usable as stub implementations.
 */
  def putIfAbsent(k: String,v: String): Option[String] = ???
  def remove(k: String,v: String): Boolean = ???
  def replace(k: String,v: String): Option[String] = ???
  def replace(k: String,oldvalue: String,newvalue: String): Boolean = ???

       val mmap = new mutable.HashMap[String, String] with collection.concurrent.Map[String, String]

So we see that instead of a simple mixin, some methods must also be implemented. Is this the best way to use concurrent.Map, or is there a better way?

所以我们看到,除了简单的mixin之外,还必须实现一些方法。这是最好的使用方法concurrent.Map,还是有更好的方法?

回答by axel22

The scala.collection.concurrent.Maptrait is not meant to be mixed-inwith an existing mutable Scala Mapto obtain a thread-safe version of the map instance. The SynchronizedMapmixin existed for this purpose before 2.11, but is now deprecated.

scala.collection.concurrent.Maptrait并不意味着与现有的可变 Scala混合Map以获得地图实例的线程安全版本。SynchronizedMapmixin 之前为此目的而存在2.11,但现在已弃用。

Currently, Scala has the scala.collection.concurrent.TrieMapimplementation for the scala.collection.concurrent.Mapinterface, but can wrap Java classes as well.

目前,Scala 具有接口的scala.collection.concurrent.TrieMap实现scala.collection.concurrent.Map,但也可以包装 Java 类。

The scala.collection.concurrent.Map, in versions prior to 2.10 known as scala.collection.mutable.ConcurrentMap, interface is used when you:

scala.collection.concurrent.Map,在之前的2.10被誉为版本scala.collection.mutable.ConcurrentMap,接口是用来当你:

  • want to implement your own concurrent, thread-safe Mapfrom scratch

  • want to wrap an existing Java concurrent map implementation:

  • Map从头开始实现自己的并发、线程安全

  • 想要包装现有的 Java 并发映射实现:

E.g:

例如:

import scala.collection._
import scala.collection.convert.decorateAsScala._
import java.util.concurrent.ConcurrentHashMap

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
  • want to write generic code that works concurrent maps, and don't want to commit to a specific implementation:
  • 想要编写适用于并发映射的通用代码,并且不想提交特定的实现:

E.g.:

例如:

import scala.collection._

def foo(map: concurrent.Map[String, String]) = map.putIfAbsent("", "")

foo(new concurrent.TrieMap)
foo(new java.util.concurrent.ConcurrentSkipListMap().asScala)
  • you could implement your own wrapper around a single-threaded mutable map implementation by using synchronized (but you would need to ensure that your program is accessing the mutable map only through this wrapper and never directly).
  • 您可以通过使用 synchronized 围绕单线程可变映射实现实现自己的包装器(但您需要确保您的程序仅通过此包装器访问可变映射,而不是直接访问)。

E.g.:

例如:

class MySynchronizedMap[K, V](private val underlying: mutable.Map[K, V])
extends concurrent.Map[K, V] {
  private val monitor = new AnyRef
  def putIfAbsent(k: K,v: V): Option[String] = monitor.synchronized {
    underlying.get(k) match {
      case s: Some[V] => s
      case None =>
        underlying(k) = v
        None
    }
  }
  def remove(k: K, v: V): Boolean = monitor.synchronized {
    underlying.get(k) match {
      case Some(v0) if v == v0 => underlying.remove(k); true
      case None => false
    }
  }
  // etc.
}

回答by Randall Schulz

Unless you want to implement a concurrent mutable hash map yourself, you have to use scala.collection.concurrent.TrieMap.

除非你想自己实现一个并发可变哈希映射,否则你必须使用scala.collection.concurrent.TrieMap.

回答by NateH06

Taken from this comment directly: https://stackoverflow.com/a/49689669/7082628

直接取自此评论:https: //stackoverflow.com/a/49689669/7082628

In 2018, apparently you can just do this:

在 2018 年,显然你可以这样做:

import java.util.concurrent.ConcurrentHashMap

val m: ConcurrentHashMap[String,MyClass] = new ConcurrentHashMap

回答by som-snytt

By "simple mixin", perhaps you're asking if the trait can be used as a decorator as shown herefor SynchronizedMap, and the answer is apparently not.

通过“简单的 mixin”,也许您是在问 trait 是否可以用作装饰器,如这里所示SynchronizedMap,而答案显然不是。

Implementations include TrieMapand the wrapper for Java's ConcurrentMap(of which there are two implementations). (Java also offers ConcurrentSkipListSetas Set.)

实现包括TrieMapJava 的包装器ConcurrentMap(其中有两个实现)。(Java 也ConcurrentSkipListSet以 Set 形式提供。)

Also see this roll-your-own question.

另请参阅此卷你自己的问题

They have you covered on the conversion side of things, if that's what you were used to:

如果您习惯了,他们会为您介绍转换方面的内容:

scala> import java.util.concurrent._
import java.util.concurrent._

scala> import collection.JavaConverters._
import collection.JavaConverters._

scala> val m = new ConcurrentHashMap[String, Int]
m: java.util.concurrent.ConcurrentHashMap[String,Int] = {}

scala> val mm = m.asScala
mm: scala.collection.concurrent.Map[String,Int] = Map()

scala> mm.replace("five",5)
res0: Option[Int] = None

scala> mm.getClass
res1: Class[_ <: scala.collection.concurrent.Map[String,Int]] = class scala.collection.convert.Wrappers$JConcurrentMapWrapper