Como escribió Daniel, parte del problema al intentar escribir en un estilo Java con Double proviene del hecho de que Double
en Scala es scala.Double
y no java.lang.Double
. Si usted quiere programar en el estilo de Java que tendría que ir a lo largo de las siguientes líneas:
//
// a) Java style, with concurrency problem
//
import java.lang.{Double=>JDouble}
import java.util.concurrent.ConcurrentHashMap
val map = new ConcurrentHashMap[String, JDouble]
def update(name: String, time: Double) {
val value: JDouble = map.get(name)
if (value eq null)
map.put(name, time)
else
map.put(name, JDouble.valueOf(value.doubleValue + time))
}
update("foo", 42.0d)
update("foo", 41.0d)
assert(map.get("foo") == 83.0d)
Scala 2.8 contiene un envoltorio Scala de ConcurrentMap
s, lo que puede evitar fácilmente el problema de java.lang.Double
vs scala.Double
. Mantendré la estructura del programa por un momento.
//
// b) Scala style, with concurrency problem.
//
import collection.JavaConversions._
import collection.mutable.ConcurrentMap
import java.util.concurrent.ConcurrentHashMap
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]()
def update(name: String, time: Double) {
map.get(name) match {
case None => map.put(name, time)
case Some(value) => map.put(name, value + time)
}
}
update("foo", 42.0d)
update("foo", 41.0d)
assert(map("foo") == 83.0d)
En la variante b) anterior no es ni el problema de representar el valor que falta como 0.0d ni el problema que java.lang.Double
no juega bien con los operadores y el boxeo. Pero ambas versiones a) yb) son cuestionables con respecto a su comportamiento de simultaneidad. El código de Mansoor usa un ConcurrentHashMap
, que tiene el propósito de permitir el acceso concurrente al mapa. En la versión original del código existe la posibilidad de que se pierda una actualización del mapa entre obtener el antiguo value
y almacenar el value + time
. Variante c) a continuación trata de evitar ese problema.
//
// c) Scala style, hopefully safe for concurrent use ;)
//
import collection.JavaConversions._
import collection.mutable.ConcurrentMap
import java.util.concurrent.ConcurrentHashMap
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]()
def update(name: String, time: Double) {
val valueOption: Option[Double] = map.putIfAbsent(name, time)
def replace(value: Double) {
val replaced = map.replace(name, value, value + time)
if (!replaced) {
replace(map(name))
}
}
valueOption foreach { replace(_) }
}
update("foo", 42.0d)
update("foo", 41.0d)
assert(map("foo") == 83.0d)
Gracias por la explicación –