web-dev-qa-db-ja.com

Scala concurrent.Mapでのミキシングのベストプラクティス

ScalaDoc は、ConcurrentMapについて次のように述べています。「非推奨(バージョン2.10.0以降)代わりにscala.collection.concurrent.Mapを使用してください。」残念ながら、 Scala docs の残りは更新されておらず、concurrentMapを参照しています。

concurrent.MapHashMapに混在させてみましたが、次の結果が得られました。

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]

そのため、単純なミックスインの代わりに、いくつかのメソッドも実装する必要があることがわかります。これはconcurrent.Mapを使用する最良の方法ですか、それともより良い方法がありますか?

29
Mike Slinn

scala.collection.concurrent.Map特性は、混在することを意図していません既存のmutable Scala Mapのスレッドセーフバージョンを取得するためのマップインスタンス。SynchronizedMap mixinは2.11の前にこの目的のために存在していましたが、現在は非推奨です。

現在、Scalaにはscala.collection.concurrent.TrieMapインターフェースのscala.collection.concurrent.Map実装がありますが、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.
}
44
axel22

並行可変ハッシュマップを自分で実装したくない場合は、scala.collection.concurrent.TrieMapを使用する必要があります。

11
Randall Schulz

このコメントから直接取得: https://stackoverflow.com/a/49689669/7082628

2018年には、明らかにこれを行うことができます:

import Java.util.concurrent.ConcurrentHashMap

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

「シンプルミックスイン」では、おそらく、特性をデコレーターとして使用できるかどうかを尋ねています ここに示すように for SynchronizedMap 、そして答えは明らかにそうではありません。

実装には、TrieMapとJavaのConcurrentMapのラッパー(そのうち2つの実装があります)が含まれます。 (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
3
som-snytt