【问题标题】:Best practices for mixing in Scala concurrent.Map在 Scala concurrent.Map 中混合的最佳实践
【发布时间】:2013-09-10 17:32:10
【问题描述】:

ScalaDoc 对 concurrentMap 的描述如下:“已弃用(自版本 2.10.0 起)请改用 scala.collection.concurrent.Map。”不幸的是,rest of the Scala docs 尚未更新,仍然引用concurrentMap

我尝试将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]

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

【问题讨论】:

    标签: scala concurrency hashmap


    【解决方案1】:

    2021 年和 Scala 2.13 的更新:

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

    import java.util.concurrent.ConcurrentHashMap
    import scala.collection.concurrent
    import scala.jdk.CollectionConverters._
    
    val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
    

    【讨论】:

      【解决方案2】:

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

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

      import java.util.concurrent.ConcurrentHashMap
      
      val m: ConcurrentHashMap[String,MyClass] = new ConcurrentHashMap
      

      【讨论】:

        【解决方案3】:

        scala.collection.concurrent.Map trait 不打算与现有的可变 Scala Map 混合 以获得地图实例的线程安全版本。 SynchronizedMap mixin 在 2.11 之前就存在于此目的,但现在已弃用。

        目前,Scala 为scala.collection.concurrent.Map 接口提供了scala.collection.concurrent.TrieMap 实现,但也可以包装Java 类。

        scala.collection.concurrent.Map,在 2.10 之前的版本中称为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.
        }
        

        【讨论】:

        • Scala 2.11 弃用同步特征
        • scala.collection.mutable.ConcurrentMap 也被弃用,取而代之的是 scala.collection.concurrent.Map;进行此更改会破坏解决方案的其余部分
        • 你能解释一下吗?您可以在上面的示例中将ConcurrentMap 替换为concurrent.Map,不是吗?
        • 我是ConcurrentMapconcurrent.Map trait 的作者,我很确定它确实有效。也许上面的代码中有一些错字,但除非你告诉我更多关于什么不起作用,否则我无能为力:(
        • 从 2.12 开始我们应该使用 import scala.collection.JavaConverters._scala.collection.convert.decorateAsScala._ 已被弃用
        【解决方案4】:

        通过“simple mixin”,也许你在问 trait 是否可以用作as shown here 的装饰器SynchronizedMap,答案显然不是。

        实现包括TrieMap 和Java 的ConcurrentMap 的包装器(其中有两个实现)。 (Java 还提供 ConcurrentSkipListSet 作为 Set。)

        另见this roll-your-own question

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

        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
        

        【讨论】:

        • 我在别处见过这个例子用中缀符号写的。 HashSet 和 WeakHashMap 的并发版本呢?它们是否已经实现,或者有没有办法将行为混合到单线程版本中?我更喜欢在单个键上同步,而不是同步整个集合
        【解决方案5】:

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

        【讨论】:

        • 并发HashSet和WeakHashMap呢?
        • 我不明白你在问什么。
        猜你喜欢
        • 1970-01-01
        • 2014-11-18
        • 1970-01-01
        • 2012-02-19
        • 2012-04-22
        • 2019-04-13
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        相关资源
        最近更新 更多