Scala bug with immutable Map in concurrent program?
I've written a Monte Carlo player for the board game Nine Men's Morris. Everything is basically immutable. The program involves lots of futures (hundreds) and a lot of modifying immutable Maps. Sometimes I get a crash with the following exception:
java.lang.NullPointerException
at scala.collection.mutable.HashTable$class.elemHashCode(HashTable.scala:154)
at scala.collection.immutable.HashMap.elemHashCode(HashMap.scala:41)
at scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:66)
at scala.collection.immutable.HashMap.findEntry(HashMap.scala:41)
at scala.collection.immutable.HashMap.undo$1(HashMap.scala:132)
at scala.collection.immutable.HashMap.undo$1(HashMap.scala:130)
at scala.collection.immutable.HashMap.makeCopy(HashMap.scala:154)
at scala.collection.immutable.HashMap.makeCopyIfUpdated(HashMap.scala:161)
at scala.collection.immutable.HashMap.update(HashMap.scala:66)
at scala.collection.immutable.Map$class.$plus(Map.scala:66)
at scala.collection.immutable.HashMap.$plus(HashMap.scala:41)
at morris.players.MapBasedMorrisBoard.applyMove(MapBasedMorrisBoard.scala:30)
at morris.players.MonteCarloPlayer$$anonfun$main$1$$anonfun$apply$1.apply(MonteCarloPlayer.scala:77)
at morris.players.MonteCarloPlayer$$anonfun$main$1$$anonfun$apply$1.apply(MonteCarloPlayer.scala:77)
at scala.actors.Futures$$anonfun$2$$anonfun$apply$1.apply(Future.scala:45)
at scala.actors.Futures$$anonfun$2$$anonfun$apply$1.apply(Future.scala:44)
at scala.actors.Reaction.run(Reaction.scala:78)
at scala.actors.FJTask$Wrap.run(Unknown Source)
at scala.actors.FJTaskRunner.scanWhileIdling(Unknown Source)
at scala.actors.FJTaskRunner.run(Unknown Source)
I'm only using immutable Maps, so I wonder whether this is caused by a bug in my own code or 开发者_高级运维maybe a bug in the scala library. When looking at the trace you can see, that there are calls to mutable HashTable further down the stack. Maybe this is causing problems with concurrency?
The code inside my program, where the exception occurs is just adding another collection to an immutable Map:
myMap ++ (someInteger -> aValue)
Edit: The same program without concurrency runs flawlessly.
I've filed a bug report for the Scala-library. As it turns out this is a known problem. The implementation of HashMap (which is used for as the standard Map type in Scala) is not suited to be used in concurrent programs since behind the scenes, it uses mutable types. This can also be observed in the stack-trace. The Scala people are hoping to replace the implementation in 2.8.
As a work-around it is suggested to use TreeHashMap, which is truly immutable. I've done this and can confirm that it works.
Link to original bug report
It can certainly cause problems with concurrency. Mix Map with SynchronizedMap, at the very least.
But note that doesn't give you any transactional guarantees. It just ensures that the Map won't break under your feet.
精彩评论