Skip to content

TrieMap method getOrElseUpdate is not thread-safe #7943

@scabug

Description

@scabug

The ScalaDoc states that a scala.collection.concurrent.TrieMap is thread-safe:

A concurrent hash-trie or TrieMap is a concurrent thread-safe lock-free implementation of a hash array mapped trie.

But the method getOrElseUpdate of scala.collection.mutable.MapLike is not overridden and is therefore not thread safe:

  def getOrElseUpdate(key: A, op: => B): B =
    get(key) match {
      case Some(v) => v
      case None => val d = op; this(key) = d; d
    }

This issue can be recreated with the following code:

import scala.collection.concurrent.TrieMap

object TrieMapApp extends App {
  object ApplyMeOnce {
    var applied = false
    def apply() = synchronized {
      require(!applied)
      applied = true
    }
  }

  val map = TrieMap.empty[String, Unit]

  val runnable = new Runnable {
    def run() = {
      try {
        map.getOrElseUpdate("Result", ApplyMeOnce())
      } catch {
        case e: Exception => exception = Some(e)
      }
    }
  }

  var exception: Option[Exception] = None

  while (exception == None) {
    1 to 10 map { i => new Thread(runnable, i.toString) } foreach { thread => thread.start() }
    println(exception)
  }
  println(exception)
}

Please let me know if you need more information.

As a workaround you can write:

synchronized { map.getOrElseUpdate("Result", ApplyMeOnce()) }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions