2013-09-06 3 views
27

Il ScalaDoc dice questo su concurrentMap: "Deprecato (dalla versione 2.10.0) Utilizzare scala.collection.concurrent.Map invece." Sfortunatamente, lo rest of the Scala docs non è stato aggiornato e fa ancora riferimento allo concurrentMap.Best practice per il mixing in Scala simultanea.Mappa

Ho cercato di mescolare in concurrent.Map in un HashMap, con i seguenti risultati:

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] 

Così vediamo che, invece di un semplice mixin, alcuni metodi devono essere implementati. È questo il modo migliore per usare concurrent.Map, o c'è un modo migliore?

risposta

34

Il scala.collection.concurrent.Map caratteristica è non destinata ad essere mescolati in con una mutevole Scala esistente Map a ottenere una versione thread-safe dell'istanza della mappa. Il mixaggio SynchronizedMap esisteva per questo scopo prima di 2.11, ma ora è deprecato.

Attualmente, Scala ha l'implementazione scala.collection.concurrent.TrieMap per l'interfaccia scala.collection.concurrent.Map, ma può anche avvolgere classi Java.

Il scala.collection.concurrent.Map, nelle versioni precedenti alla 2.10 conosciuto come scala.collection.mutable.ConcurrentMap, interfaccia viene utilizzata quando:

  • desidera implementare il proprio concorrente, thread-safe Map da zero

  • vogliono avvolgere un'implementazione esistente Java concomitante mappa:

esempio:

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

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala 
  • voglia di scrivere codice generico che funziona mappe concomitanti, e non vogliono impegnarsi per una specifica implementazione:

Ad es:

import scala.collection._ 

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

foo(new concurrent.TrieMap) 
foo(new java.util.concurrent.ConcurrentSkipListMap().asScala) 
  • è possibile implementare il proprio involucro intorno un'implementazione single-threaded mappa mutevole da utilizzando sincronizzato (ma sarebbe necessario per assicurare che il programma sta accedendo la mappa mutabile solo attraverso questo involucro e mai direttamente) .

Es .:

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 deprecate i tratti sincronizzati –

+0

Vero, modificato la risposta. – axel22

+0

scala.collection.mutable.ConcurrentMap è anche deprecato a favore di scala.collection.concurrent.Map; rendendo questa modifica incasina il resto della soluzione –

10

A meno che non si desideri implementare una mappa hash mutevole concomitante, è necessario utilizzare scala.collection.concurrent.TrieMap.

+0

Che dire HashSet concorrente e WeakHashMap? –

+3

Non capisco cosa stai chiedendo. –

2

Con "simple mixin", forse stai chiedendo se il tratto può essere usato come decoratore as shown here per SynchronizedMap, e la risposta apparentemente non è.

Le implementazioni includono TrieMap e il wrapper per Java ConcurrentMap (di cui esistono due implementazioni). (Java offre anche ConcurrentSkipListSet come Set.)

Vedere anche this roll-your-own question.

hanno coperto sul lato di conversione delle cose, se è questo che si erano abituati:

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

Ho visto questo esempio scritto con notazione infix altrove. Che dire delle versioni concorrenti di HashSet e WeakHashMap? Sono stati implementati o c'è un modo per mescolare il comportamento nella versione a thread singolo? Preferirei sincronizzare su singole chiavi, non sincronizzare l'intera collezione –