2013-09-06 3 views
27

Die ScalaDoc sagt dies über concurrentMap: "Veraltet (seit Version 2.10.0) Verwenden Sie stattdessen scala.collection.concurrent.Map." Leider wurde die rest of the Scala docs nicht aktualisiert und verweist immer noch concurrentMap.Best Practices für das Mischen in Scala Concurrent.Map

Ich habe versucht, in concurrent.Map in eine HashMap, mit den folgenden Ergebnissen zu mischen:

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 sehen wir, dass anstelle einer einfachen mixin, einige Methoden müssen auch umgesetzt werden. Ist dies der beste Weg, um concurrent.Map zu verwenden, oder gibt es einen besseren Weg?

Antwort

34

Die scala.collection.concurrent.Map Merkmal ist nicht gemischt werden in mit einem bestehenden wandelbaren Scala bedeutete Map zu eine threadsichere Version der Karteninstanz erhalten Das SynchronizedMap Mixin existierte zu diesem Zweck vor 2.11, ist aber jetzt veraltet.

Derzeit hat Scala die scala.collection.concurrent.TrieMap-Implementierung für die scala.collection.concurrent.Map-Schnittstelle, kann aber Java-Klassen auch umhüllen.

Die scala.collection.concurrent.Map, in Versionen vor 2.10 als scala.collection.mutable.ConcurrentMap bekannt, Schnittstelle wird verwendet, wenn Sie:

  • wollen Ihr eigenes gleichzeitig zu implementieren, Thread-sichere Map von Grund auf neu

  • wollen wickeln eine vorhandene Java-Karte für die gleichzeitige Implementierung:

Beispiel:

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

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala 
  • wollen generischen Code zu schreiben, die gleichzeitig Karten funktioniert, und wollen nicht auf eine spezifische Implementierung begehen:

Z.B.:

import scala.collection._ 

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

foo(new concurrent.TrieMap) 
foo(new java.util.concurrent.ConcurrentSkipListMap().asScala) 
  • Sie mithilfe synchronisiert (aber Sie müssten sicherstellen, dass Ihr Programm den Zugriff auf die wandelbaren Karte nur durch diese Wrapper und nie direkt), um Ihre eigenen Wrapper um eine Single-Threaded wandelbar Karte Implementierung implementieren könnte .

Z. B .:

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. 
} 
+2

Scala 2.11 lehnt die synchronisierten Merkmale –

+0

True, bearbeitet die Antwort. – axel22

+0

scala.collection.mutable.ConcurrentMap wird auch zugunsten von scala.collection.concurrent.Map abgelehnt; diese Änderung macht den Rest der Lösung durcheinander –

10

Sofern Sie nicht gleichzeitig eine veränderbare Hash-Karte implementieren möchten, müssen Sie scala.collection.concurrent.TrieMap verwenden.

+0

Was gleichzeitige HashSet und WeakHashMap? –

+3

Ich verstehe nicht, was Sie fragen. –

2

Mit "Simple Mixin", vielleicht fragen Sie, ob das Merkmal als Dekorateur as shown here für SynchronizedMap verwendet werden kann, und die Antwort ist offenbar nicht.

Implementierungen gehören TrieMap und der Wrapper für Java ConcurrentMap (von denen es zwei Implementierungen gibt). (Java bietet auch ConcurrentSkipListSet als Set an.)

Siehe auch this roll-your-own question.

Sie haben Sie auf der Umwandlung Seite der Dinge bedeckt, wenn es das ist, was Sie gewohnt waren:

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 
+0

Ich habe dieses Beispiel mit Infix-Notation an anderer Stelle gesehen. Was ist mit gleichzeitigen Versionen von HashSet und WeakHashMap? Wurden sie implementiert oder gibt es eine Möglichkeit, das Verhalten in die Single-Thread-Version zu integrieren? Ich würde lieber auf einzelne Schlüssel synchronisieren, nicht die gesamte Sammlung synchronisieren –