34

ScalaDoc对concurrentMap 这么说:“已弃用(自版本 2.10.0 起)scala.collection.concurrent.Map改为使用。” 不幸的是,Scala 文档的其余部分尚未更新,仍然引用concurrentMap.

我尝试混入concurrent.Mapa 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]

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

4

5 回答 5

51

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

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

在 2.10 之前的scala.collection.concurrent.Map版本中称为scala.collection.mutable.ConcurrentMap接口,当您:

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

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

例如:

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

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
  • 想要编写适用于并发映射的通用代码,并且不想提交特定的实现:

例如:

import scala.collection._

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

foo(new concurrent.TrieMap)
foo(new java.util.concurrent.ConcurrentSkipListMap().asScala)
  • 您可以使用 synchronized 围绕单线程可变映射实现实现自己的包装器(但您需要确保您的程序仅通过此包装器访问可变映射,而不是直接访问)。

例如:

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.
}
于 2014-05-11T10:20:52.243 回答
15

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

于 2013-09-06T15:50:23.050 回答
9

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

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

import java.util.concurrent.ConcurrentHashMap

val m: ConcurrentHashMap[String,MyClass] = new ConcurrentHashMap
于 2018-04-17T21:53:53.253 回答
3

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

实现包括TrieMapJava 的包装器ConcurrentMap(其中有两个实现)。(Java 也提供ConcurrentSkipListSetSet。)

另请参阅此滚动您自己的问题

如果您习惯于这样的话,他们会在转换方面为您提供帮助:

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
于 2013-09-06T23:15:30.937 回答
2

2021 年和 Scala 2.13 的更新:

包装 Java 并发映射实现时需要使用不同的隐式转换:

import java.util.concurrent.ConcurrentHashMap
import scala.collection.concurrent
import scala.jdk.CollectionConverters._

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
于 2021-01-29T13:30:57.137 回答