web-dev-qa-db-fra.com

Meilleures pratiques pour le mixage dans Scala concurrent.Map

ScalaDoc dit ceci à propos de concurrentMap: "Obsolète (depuis la version 2.10.0) Utilisez scala.collection.concurrent.Map à la place. "Malheureusement, le reste des documents Scala n'a pas été mis à jour et fait toujours référence à concurrentMap.

J'ai essayé de mélanger concurrent.Map dans un HashMap, avec les résultats suivants:

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]

On voit donc qu'au lieu d'un simple mixin, certaines méthodes doivent également être implémentées. Est-ce la meilleure façon d'utiliser concurrent.Map, ou existe-t-il un meilleur moyen?

29
Mike Slinn

Le scala.collection.concurrent.Map trait est non destiné à être mélangé avec un mutable existant Scala Map pour obtenir une version thread-safe de l'instance de carte. Le mixage SynchronizedMap existait à cet effet avant 2.11, mais est désormais obsolète.

Actuellement, Scala a le scala.collection.concurrent.TrieMap implémentation pour le scala.collection.concurrent.Map interface, mais peut encapsuler Java classes également.

Le scala.collection.concurrent.Map, dans les versions antérieures à 2.10 appelées scala.collection.mutable.ConcurrentMap, l'interface est utilisée lorsque vous:

  • souhaitez implémenter votre propre Map simultané et sans fil

  • souhaitez encapsuler une implémentation de carte simultanée existante Java:

Par exemple:

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

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
  • souhaitez écrire du code générique qui fonctionne avec des cartes simultanées et ne souhaitez pas vous engager dans une implémentation spécifique:

Par exemple.:

import scala.collection._

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

foo(new concurrent.TrieMap)
foo(new Java.util.concurrent.ConcurrentSkipListMap().asScala)
  • vous pouvez implémenter votre propre wrapper autour d'une implémentation de carte mutable à un seul thread en utilisant synchronisé (mais vous devez vous assurer que votre programme accède à la carte mutable uniquement via ce wrapper et jamais directement).

Par exemple.:

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

À moins que vous ne souhaitiez implémenter vous-même une carte de hachage mutable simultanée, vous devez utiliser scala.collection.concurrent.TrieMap.

11
Randall Schulz

Tiré de ce commentaire directement: https://stackoverflow.com/a/49689669/7082628

En 2018, apparemment, vous pouvez simplement faire ceci:

import Java.util.concurrent.ConcurrentHashMap

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

Par "simple mixin", vous demandez peut-être si le trait peut être utilisé comme décorateur comme indiqué ici pour SynchronizedMap , et la réponse est apparemment ne pas.

Les implémentations incluent TrieMap et l'encapsuleur pour Java ConcurrentMap (dont il existe deux implémentations). (Java propose également ConcurrentSkipListSet comme Set.)

Voir aussi cette question à rouler .

Ils vous couvrent du côté de la conversion, si c'est ce à quoi vous étiez habitué:

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